Compare commits

..

78 Commits

Author SHA1 Message Date
Anthony Stirling
f474651f36 lang, save to browser (#923) 2024-03-17 09:33:05 +00:00
tongkl1
11193b1b6d Fix typo in example yaml file (#922) 2024-03-16 09:49:28 +00:00
github-actions[bot]
3066b3e500 Update 3rd Party Licenses (#919)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-03-14 23:00:38 +00:00
dependabot[bot]
217f112bc4 Bump com.google.zxing:core from 3.5.2 to 3.5.3 (#779)
Bumps [com.google.zxing:core](https://github.com/zxing/zxing) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/zxing/zxing/releases)
- [Changelog](https://github.com/zxing/zxing/blob/master/CHANGES)
- [Commits](https://github.com/zxing/zxing/compare/zxing-3.5.2...zxing-3.5.3)

---
updated-dependencies:
- dependency-name: com.google.zxing:core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-03-14 22:59:27 +00:00
github-actions[bot]
e1bb0cf5ec Update 3rd Party Licenses (#914)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-03-13 22:45:32 +00:00
Anthony Stirling
3930c25a75 Frooodle patch 2 (#913)
* Update licenses-update.yml

* Update build.gradle
2024-03-13 22:34:24 +00:00
Anthony Stirling
b27e79cb52 Update build.gradle (#912) 2024-03-13 22:29:55 +00:00
Anthony Stirling
daf6486b86 Update licenses-update.yml (#911) 2024-03-13 22:26:39 +00:00
Ludy
1af41f8ea5 🔨 add Developer tools/scripts (#828)
* 🔨 add Developer tools

* Update downloader.js

* Update game.js

* Update .pre-commit-config.yaml

* Update sync_versions.yml

* removed: mixed line ending tool

* Update swagger.yml

* Update push-docker.yml

* Update build.yml

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-03-13 22:18:15 +00:00
Listiges Känguru
70e4ac21df Update messages_de_DE.properties (#903)
Added missing translations, improved some existing translations.
2024-03-13 22:11:43 +00:00
Anthony Stirling
95d9d85ca2 dep bumps and nonroot bypass (#910)
* dep bumps and nonroot bypass

* log changing
2024-03-13 22:09:56 +00:00
Ludy
9cc7a49d12 Enforcing Username Uniqueness (#906)
* Enforcing Username Uniqueness

Changes in UserService.java:

Added a new method findByUsername to allow searching for usernames regardless of case sensitivity.
Added a new method isUsernameValid to validate the username.
Changes in UserController.java:

Updated the changeUsername method to ensure the new username is valid before changing it.
Updated the editUser method to ensure the new username is unique and valid.
Changes in UserRepository.java:

Added a custom JPQL query to search for usernames regardless of case sensitivity.
Changes in HTML templates (account.html and addUsers.html):

Error messages are displayed if a username is invalid or already exists.

* JPAs auto
2024-03-13 22:09:16 +00:00
Anthony Stirling
ae73595335 Number of fixes and making pipline LIVE ! (#907)
Closes #889 and #332
#710
#901
#885
2024-03-13 19:15:10 +00:00
pavedroad
ac620082ec chore: fix some typos (#900)
Signed-off-by: pavedroad <qcqs@outlook.com>
2024-03-12 19:42:15 -04:00
Anthony Stirling
1e4134c7d1 Number fxes (#898)
* init

* user and pass to just pass lang update

* session management fixes and avoid demo user locking

* fix for UMASK and extract cleanups

* fixes for user #889 and #332

* increase session count for demo site

* fix

* gcc

* formatting

* number fixes init

* || true test

* version bump

* Hardening suggestions for Stirling-PDF / numberFxes (#899)

Switch order of literals to prevent NullPointerException

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>

---------

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
2024-03-10 14:00:00 +00:00
albanobattistella
a7bcdd0003 Update messages_it_IT.properties (#891) 2024-03-09 14:03:58 +00:00
Anthony Stirling
121af0501a fixes for user permissions (#892) 2024-03-09 14:03:46 +00:00
Ludy
82c4e9cf41 Fix TypeError by rotation (#890)
Fixes the error in the PDF multitool when rotating all pages at the same time.
2024-03-09 12:18:00 +00:00
Ludy
142e11a59a added missing translation strings (#888) 2024-03-09 08:08:33 +00:00
Anthony Stirling
08205ed32d Custom uid (#883)
* init

* user and pass to just pass lang update

* session management fixes and avoid demo user locking

* fix for UMASK and extract cleanups
2024-03-08 20:49:19 +00:00
Anthony Stirling
9246b42057 Login fixes (#881)
* init

* user and pass to just pass lang update

* session management fixes and avoid demo user locking

* Hardening suggestions for Stirling-PDF / loginFixes (#882)

Switch order of literals to prevent NullPointerException

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>

---------

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
2024-03-08 18:06:40 +00:00
albanobattistella
67e4d6e3a2 Update messages_it_IT.properties (#878) 2024-03-07 21:47:21 +00:00
Anthony Stirling
cf4613d043 Password fix and others (#875)
* init

* user and pass to just pass lang update
2024-03-07 20:12:07 +00:00
Eric
2f703796e9 fix(SplitPDF): create immutable list for dynamic additions (#877) 2024-03-07 12:05:26 -05:00
albanobattistella
731dc3f3dc Update messages_it_IT.properties (#870) 2024-03-06 22:24:30 +00:00
Ludy
97472310f2 Show the user roles as real names (#867)
* Show the user roles as real names

* Add error message

* Update Role.java

* default Language without translation

* Update messages_el_GR.properties
2024-03-06 22:14:02 +00:00
Anthony Stirling
ece1d071c0 non root user and fix book/html calibre (#856)
* non root user and fix book/html calibre

* version bump

* Update docker-compose-latest.yml

* remove customApp

---------

Co-authored-by: systo <systo@host.docker.internal>
2024-03-04 20:51:49 +00:00
albanobattistella
20f532c872 Update messages_it_IT.properties (#858)
Co-authored-by: Eric <71648843+sbplat@users.noreply.github.com>
2024-03-04 20:36:18 +00:00
Ludy
bdcccfd937 🐛 Fix: index out of bounds #861 #842 (#863)
* 🐛 Fix: `index out of bounds` #861 #842

* Update RearrangePagesPDFController.java

* Update RearrangePagesPDFController.java
2024-03-04 20:14:45 +00:00
Ludy
146b8f0103 Corrected the reading of the port. See: #834 (#855)
* Corrected the reading of the port. See: #834

* Removed outdated import

---------

Co-authored-by: Eric <71648843+sbplat@users.noreply.github.com>
2024-02-25 19:15:03 -05:00
懒猫
c8a37245fa Added option to split PDF into multiple parts and merge into one PDF (#841)
* Added option to split PDF into multiple parts and merge into one PDF

* Use the mergeDocuments method in MergeController to implement merging

---------

Co-authored-by: Eric <71648843+sbplat@users.noreply.github.com>
2024-02-24 15:26:35 -05:00
Parth P Shah
af68c70239 Update SPdfApplication.java (#853)
* Update SPdfApplication.java

* Update SPdfApplication.java

* Update SPdfApplication.java

---------

Co-authored-by: Eric <71648843+sbplat@users.noreply.github.com>
2024-02-24 15:22:47 -05:00
Ludy
5bd544dcd7 Removed: Duplicate Properties Keys pt_PT (#854) 2024-02-24 19:45:07 +00:00
Anthony Stirling
642b85069d Merge pull request #852 from parth-p-shah/application-file-fixes
Application file fixes, added loggers instead of sysout
2024-02-23 19:03:04 +00:00
Parth P Shah
6fef4ea82c Update SPdfApplication.java 2024-02-24 00:01:20 +05:30
Parth P Shah
8670afb96f Revert "Update SPdfApplication.java"
This reverts commit 33f8d60900.
2024-02-23 23:46:42 +05:30
Parth P Shah
33f8d60900 Update SPdfApplication.java 2024-02-23 23:46:36 +05:30
albanobattistella
4e2156ad79 Update messages_it_IT.properties (#839) 2024-02-21 17:30:55 -05:00
Anthony Stirling
a07245224e Merge pull request #833 from seku80/main
Add messages_pt_PT.properties
2024-02-19 22:34:00 +00:00
seku80
f96a4cdb59 Update pt_PT
Fixed missing line #14 and removing duplicate entry line #870
2024-02-19 16:46:35 +00:00
seku80
efea22aa6e Update languages.html 2024-02-19 16:19:29 +00:00
seku80
ae9a7dc580 Add files via upload 2024-02-19 16:13:16 +00:00
seku80
7135ace1aa Add files via upload 2024-02-19 15:03:28 +00:00
Anthony Stirling
625275124a fix for #818 2024-02-18 15:47:19 +00:00
Anthony Stirling
c96ebccae4 Download message for game 2024-02-18 13:30:56 +00:00
Anthony Stirling
20cb460a7e controls and sizing bounds 2024-02-18 09:45:50 +00:00
Anthony Stirling
3a62d19979 game const 2024-02-18 09:21:30 +00:00
Ludy
51ad741744 Fix 746 (#825)
* Fix: #746

* formatting
2024-02-18 07:40:30 +00:00
Anthony Stirling
673f005fe6 Game fixes and ocr docs (#824) 2024-02-17 23:23:07 +00:00
Ludy
8d9f0361d0 Fix Serbia Language (#822)
* Fix Serbia Language

* Rename messages_sr_Latn_RS.properties to messages_sr_LATN_RS.properties

* Update languages.html

* Update README.md
2024-02-17 19:56:56 +00:00
Anthony Stirling
56e3ec1219 Update HowToUseOCR.md 2024-02-17 19:28:32 +00:00
dependabot[bot]
a0acafcefc Bump org.springframework:spring-webmvc from 6.1.2 to 6.1.3 (#713)
Bumps [org.springframework:spring-webmvc](https://github.com/spring-projects/spring-framework) from 6.1.2 to 6.1.3.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.2...v6.1.3)

---
updated-dependencies:
- dependency-name: org.springframework:spring-webmvc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-17 13:24:38 +00:00
dependabot[bot]
918f5954b7 Bump io.micrometer:micrometer-core from 1.12.2 to 1.12.3 (#806)
Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.2 to 1.12.3.
- [Release notes](https://github.com/micrometer-metrics/micrometer/releases)
- [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.2...v1.12.3)

---
updated-dependencies:
- dependency-name: io.micrometer:micrometer-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-17 13:23:10 +00:00
albanobattistella
148dcdaee7 Update messages_it_IT.properties (#816) 2024-02-17 13:22:15 +00:00
Anthony Stirling
a5f0777892 Update ConfigInitializer.java for auto settings removal 2024-02-17 13:10:00 +00:00
Ludy
010426d488 Document (#803)
* Update HowToAddNewLanguage.md

* Update HowToUseOCR.md

* Update LocalRunGuide.md

* Update README.md

* Update LocalRunGuide.md

* Update README.md

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-02-16 22:42:56 +00:00
Aliarev
6fc9c7be90 Update french translation (#814) 2024-02-16 22:24:26 +00:00
Sherif Metwally
094fde9801 Update-helm-chart (#815)
* upgrade app in helm chart to 0.20.2

* update and correct UI env variable names in chart values.yaml
2024-02-16 22:23:11 +00:00
Ludy
e4a76e96af HTML, CSS, JS and JAVA corrections (#810)
* CSS corrections

* HTML corrections

* JS corrections

* JAVA corrections

* remove tab

* CSS corrections 2

* JS corrections 2

* back to the roots

* max-linie 127

* add slash hr|br

* return bootstrap-icons.css

* return bootstrap-icons.min.css

* return bootstrap.min.css

* Update bootstrap-icons.css

* Update bootstrap-icons.min.css

* Update bootstrap-icons.min.css

* Update bootstrap.min.css

* CSS corrections

* HTML corrections

* JS corrections

* JAVA corrections

* remove tab

* CSS corrections 2

* JS corrections 2

* back to the roots

* max-linie 127

* add slash hr|br

* return bootstrap-icons.css

* Update bootstrap-icons.css

* Bootstrap CSS

* Update prism.css
2024-02-16 21:49:06 +00:00
Anthony Stirling
68f582bcb9 Merge pull request #811 from NeilJared/main
Update messages_es_ES.properties
2024-02-14 21:27:59 +00:00
NeilJared
639aed7120 Update messages_es_ES.properties
Updated es_ES translation
2024-02-14 12:22:47 +01:00
NeilJared
994bb4d1d2 Update messages_es_ES.properties
Minor bug fixes: es_ES translation
2024-02-14 11:57:34 +01:00
Anthony Stirling
80b11a55fa Merge pull request #804 from Ludy87/missing_pageSelectionPrompt
add missing propertie pageSelectionPrompt
2024-02-11 22:43:08 +00:00
Ludy87
3cfb554623 missing propertie pageSelectionPrompt 2024-02-11 21:10:04 +01:00
Eric
e84f9c5946 Merge pull request #796 from Ludy87/languages
Languages
2024-02-11 14:41:15 -05:00
Ludy87
17cc31d6e7 add placeholder translation 2024-02-11 14:32:34 -05:00
Ludy87
0c6e10a6dd add separator 2024-02-11 14:32:34 -05:00
Ludy87
297c57631f remove dublicate -> change showJS.tags to autoRedact.tags 2024-02-11 14:32:34 -05:00
Ludy87
bd4e252bb6 added missing strings 2024-02-11 14:32:33 -05:00
Ludy87
0ce34c70bc Update messages_de_DE.properties 2024-02-11 14:32:33 -05:00
Ludy87
4df75cfba1 Update messages_de_DE.properties 2024-02-11 14:32:33 -05:00
Ludy87
2aa435bcfb double spaces removed 2024-02-11 14:32:33 -05:00
Ludy87
0a4a9e6947 Removed unnecessary characters and added DE missing strings 2024-02-11 14:32:32 -05:00
Anthony Stirling
d5860d0b55 Update PdfToTextOrRTFRequest.java 2024-02-11 18:47:43 +00:00
Eric
6a487ce514 Merge pull request #802 from Stirling-Tools/normalize_files
refactor: normalize all files (strip trailing whitespace + convert CRLF to LF)
2024-02-11 13:11:37 -05:00
sbplat
4f3b85e66b refactor: normalize files that contained both CRLF and LF 2024-02-11 12:14:21 -05:00
sbplat
370cd97e05 misc: update .git-blame-ignore-revs to ignore normalize files commit in blame 2024-02-11 11:54:03 -05:00
sbplat
55d4fda01b refactor: normalize files 2024-02-11 11:47:00 -05:00
259 changed files with 14001 additions and 11678 deletions

View File

@@ -1,2 +1,5 @@
# Formatting # Formatting
5f771b785130154ed47952635b7acef371ffe0ec 5f771b785130154ed47952635b7acef371ffe0ec
# Normalize files
55d4fda01b2f39f5b7d7b4fda5214bd7ff0fd5dd

51
.github/scripts/check_duplicates.py vendored Normal file
View File

@@ -0,0 +1,51 @@
import sys
def find_duplicate_keys(file_path):
"""
Finds duplicate keys in a properties file and returns their occurrences.
This function reads a properties file, identifies any keys that occur more than
once, and returns a dictionary with these keys and the line numbers of their occurrences.
Parameters:
file_path (str): The path to the properties file to be checked.
Returns:
dict: A dictionary where each key is a duplicated key in the file, and the value is a list
of line numbers where the key occurs.
"""
with open(file_path, "r", encoding="utf-8") as file:
lines = file.readlines()
keys = {}
duplicates = {}
for line_number, line in enumerate(lines, start=1):
line = line.strip()
if line and not line.startswith("#") and "=" in line:
key = line.split("=", 1)[0].strip()
if key in keys:
# If the key already exists, add the current line number
duplicates.setdefault(key, []).append(line_number)
# Also add the first instance of the key if not already done
if keys[key] not in duplicates[key]:
duplicates[key].insert(0, keys[key])
else:
# Store the line number of the first instance of the key
keys[key] = line_number
return duplicates
if __name__ == "__main__":
failed = False
for ar in sys.argv[1:]:
duplicates = find_duplicate_keys(ar)
if duplicates:
for key, lines in duplicates.items():
lines_str = ", ".join(map(str, lines))
print(f"{key} duplicated in {ar} on lines {lines_str}")
failed = True
if failed:
sys.exit(1)

84
.github/scripts/check_tabulator.py vendored Normal file
View File

@@ -0,0 +1,84 @@
"""check_tabulator.py"""
import argparse
import sys
def check_tabs(file_path):
"""
Checks for tabs in the specified file.
Args:
file_path (str): The path to the file to be checked.
Returns:
bool: True if tabs are found, False otherwise.
"""
with open(file_path, "r", encoding="utf-8") as file:
content = file.read()
if "\t" in content:
print(f"Tab found in {file_path}")
return True
return False
def replace_tabs_with_spaces(file_path, replace_with=" "):
"""
Replaces tabs with a specified number of spaces in the file.
Args:
file_path (str): The path to the file where tabs will be replaced.
replace_with (str): The character(s) to replace tabs with. Defaults to two spaces.
"""
with open(file_path, "r", encoding="utf-8") as file:
content = file.read()
updated_content = content.replace("\t", replace_with)
with open(file_path, "w", encoding="utf-8") as file:
file.write(updated_content)
def main():
"""
Main function to replace tabs with spaces in the provided files.
The replacement character and files to check are taken from command line arguments.
"""
# Create ArgumentParser instance
parser = argparse.ArgumentParser(
description="Replace tabs in files with specified characters."
)
# Define optional argument `--replace_with`
parser.add_argument(
"--replace_with",
default=" ",
help="Character(s) to replace tabs with. Default is two spaces.",
)
# Define argument for file paths
parser.add_argument("files", metavar="FILE", nargs="+", help="Files to process.")
# Parse arguments
args = parser.parse_args()
# Extract replacement characters and files from the parsed arguments
replace_with = args.replace_with
files_checked = args.files
error = False
for file_path in files_checked:
if check_tabs(file_path):
replace_tabs_with_spaces(file_path, replace_with)
error = True
if error:
print("Error: Originally found tabs in HTML files, now replaced.")
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main()

67
.github/scripts/gradle_to_chart.py vendored Normal file
View File

@@ -0,0 +1,67 @@
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 appVersion from Chart.yaml.
Args:
path (str): The file path to the Chart.yaml.
Returns:
str: The appVersion if found, otherwise an empty string.
"""
with open(path, encoding="utf-8") as file:
chart_yaml = yaml.safe_load(file)
return chart_yaml.get("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 update_chart_version(path, new_version):
"""
Updates the appVersion in Chart.yaml with a new version.
Args:
path (str): The file path to the Chart.yaml.
new_version (str): The new version to update to.
"""
with open(path, encoding="utf-8") as file:
chart_yaml = yaml.safe_load(file)
chart_yaml["appVersion"] = new_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 != gradle_version:
print(
f"Versions do not match. Updating Chart.yaml from {chart_version} to {gradle_version}."
)
update_chart_version(chart_yaml_path, gradle_version)
else:
print("Versions match. No update required.")

View File

@@ -3,8 +3,14 @@ name: "Build repo"
on: on:
push: push:
branches: [ "main" ] branches: [ "main" ]
paths-ignore:
- ".github/**"
- "**/*.md"
pull_request: pull_request:
branches: [ "main" ] branches: [ "main" ]
paths-ignore:
- ".github/**"
- "**/*.md"
jobs: jobs:
build: build:

View File

@@ -32,17 +32,30 @@ jobs:
run: | run: |
mv build/reports/dependency-license/index.json src/main/resources/static/3rdPartyLicenses.json mv build/reports/dependency-license/index.json src/main/resources/static/3rdPartyLicenses.json
- name: Check for Changes - name: Set up git config
id: git-check run: |
git config --global user.email "GitHub Action <action@github.com>"
git config --global user.name "GitHub Action <action@github.com>"
- name: Run git add
run: | run: |
git add src/main/resources/static/3rdPartyLicenses.json git add src/main/resources/static/3rdPartyLicenses.json
git diff --staged --exit-code || echo "changes=true" >> $GITHUB_ENV git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
- name: Commit and Push Changes - name: Create Pull Request
if: env.changes == 'true' if: env.CHANGES_DETECTED == 'true'
run: | uses: peter-evans/create-pull-request@v3
git config --global user.name 'Stirling-PDF-Bot' with:
git config --global user.email 'Stirling-PDF-Bot@stirlingtools.com' token: ${{ secrets.GITHUB_TOKEN }}
git commit -m "Update 3rd Party Licenses" commit-message: "Update 3rd Party Licenses"
git push committer: GitHub Action <action@github.com>
author: GitHub Action <action@github.com>
signoff: true
branch: update-3rd-party-licenses
title: "Update 3rd Party Licenses"
body: |
Auto-generated by [create-pull-request][1]
[1]: https://github.com/peter-evans/create-pull-request
draft: false
delete-branch: true

View File

@@ -3,9 +3,13 @@ name: Push Docker Image with VersionNumber
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: branches:
- master - master
- main - main
paths-ignore:
- ".github/**"
- "**/*.md"
permissions: permissions:
contents: read contents: read
packages: write packages: write
@@ -15,13 +19,13 @@ jobs:
steps: steps:
- uses: actions/checkout@v3.5.2 - uses: actions/checkout@v3.5.2
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v3.11.0 uses: actions/setup-java@v3.11.0
with: with:
java-version: '17' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- uses: gradle/gradle-build-action@v2.4.2 - uses: gradle/gradle-build-action@v2.4.2
env: env:
@@ -32,11 +36,11 @@ jobs:
- name: Make Gradle wrapper executable - name: Make Gradle wrapper executable
run: chmod +x gradlew run: chmod +x gradlew
- name: Get version number - name: Get version number
id: versionNumber id: versionNumber
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)" run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v2.1.0 uses: docker/login-action@v2.1.0
with: with:
@@ -53,7 +57,7 @@ jobs:
- name: Convert repository owner to lowercase - name: Convert repository owner to lowercase
id: repoowner id: repoowner
run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')" run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')"
- name: Generate tags - name: Generate tags
id: meta id: meta
uses: docker/metadata-action@v4.4.0 uses: docker/metadata-action@v4.4.0
@@ -82,7 +86,7 @@ jobs:
cache-to: type=gha,mode=max cache-to: type=gha,mode=max
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
build-args: build-args:
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64,linux/arm64/v8 platforms: linux/amd64,linux/arm64/v8
@@ -99,7 +103,7 @@ jobs:
tags: | tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }} 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' }} type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
- name: Build and push Dockerfile-ultra-lite - name: Build and push Dockerfile-ultra-lite
uses: docker/build-push-action@v4.0.0 uses: docker/build-push-action@v4.0.0
@@ -112,7 +116,7 @@ jobs:
cache-to: type=gha,mode=max cache-to: type=gha,mode=max
tags: ${{ steps.meta2.outputs.tags }} tags: ${{ steps.meta2.outputs.tags }}
labels: ${{ steps.meta2.outputs.labels }} labels: ${{ steps.meta2.outputs.labels }}
build-args: build-args:
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64,linux/arm64/v8 platforms: linux/amd64,linux/arm64/v8
@@ -129,7 +133,7 @@ jobs:
tags: | tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-lite,enable=${{ github.ref == 'refs/heads/master' }} type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-lite,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=latest-lite,enable=${{ github.ref == 'refs/heads/master' }} type=raw,value=latest-lite,enable=${{ github.ref == 'refs/heads/master' }}
- name: Build and push Dockerfile-lite - name: Build and push Dockerfile-lite
uses: docker/build-push-action@v4.0.0 uses: docker/build-push-action@v4.0.0
@@ -142,7 +146,7 @@ jobs:
cache-to: type=gha,mode=max cache-to: type=gha,mode=max
tags: ${{ steps.meta3.outputs.tags }} tags: ${{ steps.meta3.outputs.tags }}
labels: ${{ steps.meta3.outputs.labels }} labels: ${{ steps.meta3.outputs.labels }}
build-args: build-args:
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64,linux/arm64/v8 platforms: linux/amd64,linux/arm64/v8
- name: Build and Push Helm Chart - name: Build and Push Helm Chart

View File

@@ -1,7 +1,7 @@
name: Release Artifacts name: Release Artifacts
on: on:
release: release:
types: [created] types: [created]
permissions: permissions:
contents: write contents: write
@@ -19,13 +19,13 @@ jobs:
file_suffix: '' file_suffix: ''
steps: steps:
- uses: actions/checkout@v3.5.2 - uses: actions/checkout@v3.5.2
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v3.11.0 uses: actions/setup-java@v3.11.0
with: with:
java-version: '17' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- name: Grant execute permission for gradlew - name: Grant execute permission for gradlew
run: chmod +x gradlew run: chmod +x gradlew
@@ -42,11 +42,11 @@ jobs:
asset_name: Stirling-PDF${{ matrix.file_suffix }}.exe asset_name: Stirling-PDF${{ matrix.file_suffix }}.exe
tag: ${{ github.ref }} tag: ${{ github.ref }}
overwrite: true overwrite: true
- name: Get version number - name: Get version number
id: versionNumber id: versionNumber
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)" run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
- name: Upload jar binaries to release - name: Upload jar binaries to release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
with: with:

View File

@@ -3,8 +3,11 @@ name: Update Swagger
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: branches:
- master - master
paths-ignore:
- ".github/**"
- "**/*.md"
jobs: jobs:
push: push:
@@ -12,13 +15,13 @@ jobs:
steps: steps:
- uses: actions/checkout@v3.5.2 - uses: actions/checkout@v3.5.2
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v3.11.0 uses: actions/setup-java@v3.11.0
with: with:
java-version: '17' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- name: Grant execute permission for gradlew - name: Grant execute permission for gradlew
run: chmod +x gradlew run: chmod +x gradlew

51
.github/workflows/sync_versions.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Sync Versions
on:
push:
branches:
- main
paths:
- "build.gradle"
permissions:
contents: write
pull-requests: write
jobs:
sync-versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.1
- name: Set up Python
uses: actions/setup-python@v5.0.0
with:
python-version: '3.x'
- name: Install dependencies
run: pip install pyyaml
- name: Sync versions
run: python .github/scripts/gradle_to_chart.py
- name: Set up git config
run: |
git config --global user.email "GitHub Action <action@github.com>"
git config --global user.name "GitHub Action <action@github.com>"
- name: Run git add
run: |
git add .
git diff --staged --quiet || git commit -m ":floppy_disk: Sync Versions
> Made via sync_versions.yml" || echo "no changes"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6.0.0
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

View File

@@ -30,7 +30,7 @@ jobs:
- name: Run Docker Compose Tests - name: Run Docker Compose Tests
run: | run: |
chmod +x ./gradlew chmod +x ./gradlew
- name: Get version number - name: Get version number
id: versionNumber id: versionNumber
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)" run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"

252
.gitignore vendored
View File

@@ -1,127 +1,127 @@
### Eclipse ### ### Eclipse ###
.metadata .metadata
bin/ bin/
tmp/ tmp/
*.tmp *.tmp
*.bak *.bak
*.swp *.swp
*~.nib *~.nib
local.properties local.properties
.settings/ .settings/
.loadpath .loadpath
.recommenders .recommenders
.classpath .classpath
.project .project
version.properties version.properties
pipeline/watchedFolders/ pipeline/watchedFolders/
pipeline/finishedFolders/ pipeline/finishedFolders/
#### Stirling-PDF Files ### #### Stirling-PDF Files ###
customFiles/ customFiles/
configs/ configs/
watchedFolders/ watchedFolders/
# Gradle # Gradle
.gradle .gradle
.lock .lock
# External tool builders # External tool builders
.externalToolBuilders/ .externalToolBuilders/
# Locally stored "Eclipse launch configurations" # Locally stored "Eclipse launch configurations"
*.launch *.launch
# PyDev specific (Python IDE for Eclipse) # PyDev specific (Python IDE for Eclipse)
*.pydevproject *.pydevproject
# CDT-specific (C/C++ Development Tooling) # CDT-specific (C/C++ Development Tooling)
.cproject .cproject
# CDT- autotools # CDT- autotools
.autotools .autotools
# Java annotation processor (APT) # Java annotation processor (APT)
.factorypath .factorypath
# PDT-specific (PHP Development Tools) # PDT-specific (PHP Development Tools)
.buildpath .buildpath
# sbteclipse plugin # sbteclipse plugin
.target .target
# Tern plugin # Tern plugin
.tern-project .tern-project
# TeXlipse plugin # TeXlipse plugin
.texlipse .texlipse
# STS (Spring Tool Suite) # STS (Spring Tool Suite)
.springBeans .springBeans
# Code Recommenders # Code Recommenders
.recommenders/ .recommenders/
# Annotation Processing # Annotation Processing
.apt_generated/ .apt_generated/
.apt_generated_test/ .apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse) # Scala IDE specific (Scala & Java development for Eclipse)
.cache-main .cache-main
.scala_dependencies .scala_dependencies
.worksheet .worksheet
# Uncomment this line if you wish to ignore the project description file. # Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations: # Typically, this file would be tracked if it contains build/dependency configurations:
#.project #.project
### Eclipse Patch ### ### Eclipse Patch ###
# Spring Boot Tooling # Spring Boot Tooling
.sts4-cache/ .sts4-cache/
### Git ### ### Git ###
# Created by git for backups. To disable backups in Git: # Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false # $ git config --global mergetool.keepBackup false
*.orig *.orig
# Created by git when using merge tools for conflicts # Created by git when using merge tools for conflicts
*.BACKUP.* *.BACKUP.*
*.BASE.* *.BASE.*
*.LOCAL.* *.LOCAL.*
*.REMOTE.* *.REMOTE.*
*_BACKUP_*.txt *_BACKUP_*.txt
*_BASE_*.txt *_BASE_*.txt
*_LOCAL_*.txt *_LOCAL_*.txt
*_REMOTE_*.txt *_REMOTE_*.txt
### Java ### ### Java ###
# Compiled class file # Compiled class file
*.class *.class
# Log file # Log file
*.log *.log
# BlueJ files # BlueJ files
*.ctxt *.ctxt
# Mobile Tools for Java (J2ME) # Mobile Tools for Java (J2ME)
.mtj.tmp/ .mtj.tmp/
# Package Files # # Package Files #
*.jar *.jar
*.war *.war
*.nar *.nar
*.ear *.ear
*.zip *.zip
*.tar.gz *.tar.gz
*.rar *.rar
*.db *.db
/build /build
/.vscode /.vscode
/.idea /.idea
# Ignore Mac DS_Store files # Ignore Mac DS_Store files
.DS_Store .DS_Store
**/.DS_Store **/.DS_Store

37
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,37 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.1
hooks:
- id: ruff
args:
- --fix
- --line-length=127
files: ^((.github/scripts)/.+)?[^/]+\.py$
- id: ruff-format
files: ^((.github/scripts)/.+)?[^/]+\.py$
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
hooks:
- id: codespell
args:
- --ignore-words-list=
- --skip="./.*,*.csv,*.json,*.ambr"
- --quiet-level=2
files: \.(properties|html|css|js|py|md)$
exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile)
- repo: local
hooks:
- id: check-duplicate-properties-keys
name: Check Duplicate Properties Keys
entry: python .github/scripts/check_duplicates.py
language: python
files: ^(src)/.+\.properties$
- repo: local
hooks:
- id: check-html-tabs
name: Check HTML for tabs
# args: ["--replace_with= "]
entry: python .github/scripts/check_tabulator.py
language: python
exclude: ^src/main/resources/static/pdfjs/
files: ^.*(\.html|\.css|\.js)$

View File

@@ -1,69 +1,63 @@
# Main stage # Main stage
FROM alpine:3.19.1 FROM alpine:3.19.1
# JDK for app # Copy necessary files
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \ COPY scripts /scripts
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \ COPY pipeline /pipeline
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \ COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto
apk add --no-cache \ COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto
ca-certificates \ COPY build/libs/*.jar app.jar
tzdata \
tini \ ARG VERSION_TAG
bash \
curl \
openjdk17-jre \ # Set Environment Variables
# Doc conversion ENV DOCKER_ENABLE_SECURITY=false \
libreoffice@testing \ VERSION_TAG=$VERSION_TAG \
# OCR MY PDF (unpaper for descew and other advanced featues) JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
ocrmypdf \ HOME=/home/stirlingpdfuser \
tesseract-ocr-data-eng \ PUID=1000 \
# CV PGID=1000 \
py3-opencv \ UMASK=022
# python3/pip
python3 && \
wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \ # JDK for app
# uno unoconv and HTML RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \ echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
mv /usr/share/tessdata /usr/share/tessdata-original echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
apk add --no-cache \
ca-certificates \
tzdata \
ARG VERSION_TAG tini \
bash \
# Set Environment Variables curl \
ENV DOCKER_ENABLE_SECURITY=false \ openjdk17-jre \
HOME=/home/stirlingpdfuser \ su-exec \
VERSION_TAG=$VERSION_TAG \ shadow \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" # Doc conversion
# PUID=1000 \ libreoffice@testing \
# PGID=1000 \ # OCR MY PDF (unpaper for descew and other advanced featues)
# UMASK=022 \ ocrmypdf \
tesseract-ocr-data-eng \
# Copy necessary files # CV
COPY scripts /scripts py3-opencv \
COPY pipeline /pipeline # python3/pip
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto python3 && \
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \
COPY build/libs/*.jar app.jar # uno unoconv and HTML
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \
# Create user and group mv /usr/share/tessdata /usr/share/tessdata-original && \
##RUN groupadd -g $PGID stirlingpdfgroup && \ mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
## useradd -u $PUID -g stirlingpdfgroup -s /bin/sh stirlingpdfuser && \ fc-cache -f -v && \
## mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME && \ chmod +x /scripts/* && \
# Set up necessary directories and permissions chmod +x /scripts/init.sh && \
RUN mkdir -p /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \ # User permissions
##&& \ addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
## chown -R stirlingpdfuser:stirlingpdfgroup /scripts /usr/share/fonts/opentype/noto /usr/share/tesseract-ocr /configs /customFiles && \ chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
## chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/tesseract-ocr-original && \ chown stirlingpdfuser:stirlingpdfgroup /app.jar
# Set font cache and permissions
fc-cache -f -v && \ EXPOSE 8080
chmod +x /scripts/*
## chown stirlingpdfuser:stirlingpdfgroup /app.jar && \ # Set user and run command
## chmod +x /scripts/init.sh ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]
EXPOSE 8080
# Set user and run command
##USER stirlingpdfuser
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]

View File

@@ -7,10 +7,10 @@ ARG VERSION_TAG
ENV DOCKER_ENABLE_SECURITY=false \ ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \ HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \ VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
# PUID=1000 \ PUID=1000 \
# PGID=1000 \ PGID=1000 \
# UMASK=022 \ UMASK=022
# Copy necessary files # Copy necessary files
COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh
@@ -29,7 +29,10 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
tini \ tini \
bash \ bash \
curl \ curl \
gcc \
openjdk17-jre \ openjdk17-jre \
su-exec \
shadow \
# Doc conversion # Doc conversion
libreoffice@testing \ libreoffice@testing \
# python and pip # python and pip
@@ -37,17 +40,16 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \ wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \
# uno unoconv and HTML # uno unoconv and HTML
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \ pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \
# Create user and group
#RUN groupadd -g $PGID stirlingpdfgroup && \
# useradd -u $PUID -g stirlingpdfgroup -s /bin/sh stirlingpdfuser && \
# mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME
# Set up necessary directories and permissions # Set up necessary directories and permissions
mkdir -p /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \ mkdir -p /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
# chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/fonts/opentype/noto /configs /customFiles
# Set font cache and permissions # Set font cache and permissions
fc-cache -f -v && \ fc-cache -f -v && \
chmod +x /scripts/*.sh chmod +x /scripts/*.sh && \
# chown stirlingpdfuser:stirlingpdfgroup /app.jar # User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
# Set environment variables # Set environment variables
ENV ENDPOINTS_GROUPS_TO_REMOVE=OpenCV,OCRmyPDF ENV ENDPOINTS_GROUPS_TO_REMOVE=OpenCV,OCRmyPDF
@@ -56,6 +58,6 @@ ENV DOCKER_ENABLE_SECURITY=false
EXPOSE 8080 EXPOSE 8080
# Run the application # Run the application
#USER stirlingpdfuser
ENTRYPOINT ["tini", "--", "/scripts/init-without-ocr.sh"] ENTRYPOINT ["tini", "--", "/scripts/init-without-ocr.sh"]
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"] CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]

View File

@@ -7,10 +7,10 @@ ARG VERSION_TAG
ENV DOCKER_ENABLE_SECURITY=false \ ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \ HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \ VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
# PUID=1000 \ PUID=1000 \
# PGID=1000 \ PGID=1000 \
# UMASK=022 \ UMASK=022
# Copy necessary files # Copy necessary files
COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh
@@ -18,16 +18,10 @@ COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
COPY pipeline /pipeline COPY pipeline /pipeline
COPY build/libs/*.jar app.jar COPY build/libs/*.jar app.jar
# Create user and group using Alpine's addgroup and adduser
#RUN addgroup -g $PGID stirlingpdfgroup && \
# adduser -u $PUID -G stirlingpdfgroup -s /bin/sh -D stirlingpdfuser && \
# mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME
# Set up necessary directories and permissions # Set up necessary directories and permissions
#RUN mkdir -p /scripts /configs /customFiles && \
# chown -R stirlingpdfuser:stirlingpdfgroup /scripts /configs /customFiles /logs /pipeline /pipeline/defaultWebUIConfigs /pipeline/watchedFolders /pipeline/finishedFolders
RUN mkdir /configs /logs /customFiles && \ RUN mkdir /configs /logs /customFiles && \
# Set font cache and permissions
#RUN chown stirlingpdfuser:stirlingpdfgroup /app.jar
chmod +x /scripts/*.sh && \ chmod +x /scripts/*.sh && \
apk add --no-cache \ apk add --no-cache \
ca-certificates \ ca-certificates \
@@ -35,10 +29,16 @@ RUN mkdir /configs /logs /customFiles && \
tini \ tini \
bash \ bash \
curl \ curl \
su-exec \
shadow \
openjdk17-jre && \ openjdk17-jre && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \ echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \ echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
# User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /configs /customFiles /pipeline && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
# Set environment variables # Set environment variables
ENV ENDPOINTS_GROUPS_TO_REMOVE=CLI ENV ENDPOINTS_GROUPS_TO_REMOVE=CLI

View File

@@ -1,46 +1,46 @@
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript | | Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------| |---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------|
| adjust-contrast | ✔️ | | | | | | | | | | ✔️ | | adjust-contrast | ✔️ | | | | | | | | | | ✔️ |
| auto-split-pdf | ✔️ | | | | | | | | | ✔️ | | | auto-split-pdf | ✔️ | | | | | | | | | ✔️ | |
| crop | ✔️ | | | | | | | | | ✔️ | | | crop | ✔️ | | | | | | | | | ✔️ | |
| extract-page | ✔️ | | | | | | | | | ✔️ | | | extract-page | ✔️ | | | | | | | | | ✔️ | |
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | | | merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | | | multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ | | pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | | | pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | |
| remove-pages | ✔️ | | | | | | | | | ✔️ | | | remove-pages | ✔️ | | | | | | | | | ✔️ | |
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | | | rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
| scale-pages | ✔️ | | | | | | | | | ✔️ | | | scale-pages | ✔️ | | | | | | | | | ✔️ | |
| split-pdfs | ✔️ | | | | | | | | | ✔️ | | | split-pdfs | ✔️ | | | | | | | | | ✔️ | |
| file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | | | file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| img-to-pdf | | ✔️ | | | | | | | | ✔️ | | | img-to-pdf | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | | | pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | | | pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | | | pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | | | pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | |
| xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | | | xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| add-password | | | ✔️ | | | | | | | ✔️ | | | add-password | | | ✔️ | | | | | | | ✔️ | |
| add-watermark | | | ✔️ | | | | | | | ✔️ | | | add-watermark | | | ✔️ | | | | | | | ✔️ | |
| cert-sign | | | ✔️ | | | | | | | ✔️ | | | cert-sign | | | ✔️ | | | | | | | ✔️ | |
| change-permissions | | | ✔️ | | | | | | | ✔️ | | | change-permissions | | | ✔️ | | | | | | | ✔️ | |
| remove-password | | | ✔️ | | | | | | | ✔️ | | | remove-password | | | ✔️ | | | | | | | ✔️ | |
| sanitize-pdf | | | ✔️ | | | | | | | ✔️ | | | sanitize-pdf | | | ✔️ | | | | | | | ✔️ | |
| add-image | | | | ✔️ | | | | | | ✔️ | | | add-image | | | | ✔️ | | | | | | ✔️ | |
| add-page-numbers | | | | ✔️ | | | | | | ✔️ | | | add-page-numbers | | | | ✔️ | | | | | | ✔️ | |
| auto-rename | | | | ✔️ | | | | | | ✔️ | | | auto-rename | | | | ✔️ | | | | | | ✔️ | |
| change-metadata | | | | ✔️ | | | | | | ✔️ | | | change-metadata | | | | ✔️ | | | | | | ✔️ | |
| compare | | | | ✔️ | | | | | | | ✔️ | | compare | | | | ✔️ | | | | | | | ✔️ |
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | | | compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | | | extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| extract-images | | | | ✔️ | | | | | | ✔️ | | | extract-images | | | | ✔️ | | | | | | ✔️ | |
| flatten | | | | ✔️ | | | | | | | ✔️ | | flatten | | | | ✔️ | | | | | | | ✔️ |
| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | | | get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | |
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | | | ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | | | remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | | | repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
| show-javascript | | | | ✔️ | | | | | | | ✔️ | | show-javascript | | | | ✔️ | | | | | | | ✔️ |
| sign | | | | ✔️ | | | | | | | ✔️ | | sign | | | | ✔️ | | | | | | | ✔️ |

View File

@@ -1,13 +1,5 @@
## User Guide for Local Directory Scanning and File Processing ## User Guide for Local Directory Scanning and File Processing
### Whilst Pipelines are in alpha...
You must enable this alpha functionality by setting
```yaml
system:
enableAlphaFunctionality: true
```
To true like in the above for your `/config/settings.yml` file, after restarting Stirling-PDF you should see both UI and folder scanning enabled.
### Setting Up Watched Folders: ### Setting Up Watched Folders:
- Create a folder where you want your files to be monitored. This is your 'watched folder'. - Create a folder where you want your files to be monitored. This is your 'watched folder'.
- The default directory for this is `./pipeline/watchedFolders/` - The default directory for this is `./pipeline/watchedFolders/`

View File

@@ -9,13 +9,13 @@ Fork Stirling-PDF and make a new branch out of Main
Then add reference to the language in the navbar by adding a new language entry to the dropdown Then add reference to the language in the navbar by adding a new language entry to the dropdown
https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/templates/fragments/languages.html https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/templates/fragments/languages.html
and add a flag svg file to and add a flag svg file to
https://github.com/Stirling-Tools/Stirling-PDF/tree/main/src/main/resources/static/images/flags https://github.com/Stirling-Tools/Stirling-PDF/tree/main/src/main/resources/static/images/flags
Any SVG flags are fine, i got most of mine from [here](https://flagicons.lipis.dev/) Any SVG flags are fine, i got most of mine from [here](https://flagicons.lipis.dev/)
If your language isnt represented by a flag just find whichever closely matches it, such as for Arabic i chose Saudi Arabia If your language isn't represented by a flag just find whichever closely matches it, such as for Arabic i chose Saudi Arabia
For example to add Polish you would add For example to add Polish you would add
```html ```html
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="pl_PL"> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="pl_PL">
<img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski <img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski
@@ -23,7 +23,7 @@ For example to add Polish you would add
``` ```
The data-language-code is the code used to reference the file in the next step. The data-language-code is the code used to reference the file in the next step.
Start by copying the existing english property file Start by copying the existing english property file
[https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties) [https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties)
@@ -32,7 +32,7 @@ Copy and rename it to messages_{your data-language-code here}.properties, in the
Then simply translate all property entries within that file and make a PR into main for others to use! Then simply translate all property entries within that file and make a PR into main for others to use!
If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but wont be able to verify the translations themselves) If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but won't be able to verify the translations themselves)

View File

@@ -2,12 +2,12 @@
This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker. This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker.
## My OCR used to work and now doesnt! ## My OCR used to work and now doesn't!
Please update your tesseract docker volume path version from 4.00 to 5 The paths have changed for the tessadata locations on new docker images, please use ``/usr/share/tessdata`` (Others should still work for backwards compatibility but might not)
## How does the OCR Work ## How does the OCR Work
Stirling-PDF uses [OCRmyPDF](https://github.com/ocrmypdf/OCRmyPDF) which in turn uses tesseract for its text recognition. Stirling-PDF uses [OCRmyPDF](https://github.com/ocrmypdf/OCRmyPDF) which in turn uses tesseract for its text recognition.
All credit goes to them for this awesome work! All credit goes to them for this awesome work!
## Language Packs ## Language Packs
@@ -27,7 +27,7 @@ Depending on your requirements, you can choose the appropriate language pack for
#### Docker #### Docker
If you are using Docker, you need to expose the Tesseract tessdata directory as a volume in order to use the additional language packs. If you are using Docker, you need to expose the Tesseract tessdata directory as a volume in order to use the additional language packs.
#### Docker Compose #### Docker Compose
Modify your `docker-compose.yml` file to include the following volume configuration: Modify your `docker-compose.yml` file to include the following volume configuration:

88
Jenkinsfile vendored
View File

@@ -1,45 +1,45 @@
pipeline { pipeline {
agent any agent any
stages { stages {
stage('Build') { stage('Build') {
steps { steps {
sh 'chmod 755 gradlew' sh 'chmod 755 gradlew'
sh './gradlew build' sh './gradlew build'
} }
} }
stage('Docker Build') { stage('Docker Build') {
steps { steps {
script { script {
def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim() def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim()
def image = "frooodle/s-pdf:$appVersion" def image = "frooodle/s-pdf:$appVersion"
sh "docker build -t $image ." sh "docker build -t $image ."
} }
} }
} }
stage('Docker Push') { stage('Docker Push') {
steps { steps {
script { script {
def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim() def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim()
def image = "frooodle/s-pdf:$appVersion" def image = "frooodle/s-pdf:$appVersion"
withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) { withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) {
sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN" sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN"
sh "docker push $image" sh "docker push $image"
} }
} }
} }
} }
stage('Helm Push') { stage('Helm Push') {
steps { steps {
script { script {
//TODO: Read chartVersion from Chart.yaml //TODO: Read chartVersion from Chart.yaml
def chartVersion = '1.0.0' def chartVersion = '1.0.0'
withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) { withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) {
sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN" sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN"
sh "helm package chart/stirling-pdf" sh "helm package chart/stirling-pdf"
sh "helm push stirling-pdf-chart-1.0.0.tgz oci://registry-1.docker.io/frooodle" sh "helm push stirling-pdf-chart-1.0.0.tgz oci://registry-1.docker.io/frooodle"
} }
} }
} }
} }
} }
} }

View File

@@ -45,7 +45,7 @@ sudo apt-get update
sudo apt-get install -y git automake autoconf libtool libleptonica-dev pkg-config zlib1g-dev make g++ java-17-openjdk python3 python3-pip sudo apt-get install -y git automake autoconf libtool libleptonica-dev pkg-config zlib1g-dev make g++ java-17-openjdk python3 python3-pip
``` ```
For Fedora-based systems use this command: For Fedora-based systems use this command:
```bash ```bash
sudo dnf install -y git automake autoconf libtool leptonica-devel pkg-config zlib-devel make gcc-c++ java-17-openjdk python3 python3-pip sudo dnf install -y git automake autoconf libtool leptonica-devel pkg-config zlib-devel make gcc-c++ java-17-openjdk python3 python3-pip
@@ -65,7 +65,7 @@ sudo make install
``` ```
### Step 3: Install Additional Software ### Step 3: Install Additional Software
Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for patern recognition functionality. Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for pattern recognition functionality.
Install the following software: Install the following software:
@@ -95,14 +95,14 @@ For Debian-based systems, you can use the following command:
```bash ```bash
sudo apt-get install -y libreoffice-writer libreoffice-calc libreoffice-impress unpaper ocrmypdf sudo apt-get install -y libreoffice-writer libreoffice-calc libreoffice-impress unpaper ocrmypdf
pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint
``` ```
For Fedora: For Fedora:
```bash ```bash
sudo dnf install -y libreoffice-writer libreoffice-calc libreoffice-impress unpaper ocrmypdf sudo dnf install -y libreoffice-writer libreoffice-calc libreoffice-impress unpaper ocrmypdf
pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint
``` ```
### Step 4: Clone and Build Stirling-PDF ### Step 4: Clone and Build Stirling-PDF
@@ -140,7 +140,7 @@ Manual:
1. Download the desired language pack(s) by selecting the `.traineddata` file(s) for the language(s) you need. 1. Download the desired language pack(s) by selecting the `.traineddata` file(s) for the language(s) you need.
2. Place the `.traineddata` files in the Tesseract tessdata directory: `/usr/share/tessdata` 2. Place the `.traineddata` files in the Tesseract tessdata directory: `/usr/share/tessdata`
3. 3.
Please view [OCRmyPDF install guide](https://ocrmypdf.readthedocs.io/en/latest/installation.html) for more info. Please view [OCRmyPDF install guide](https://ocrmypdf.readthedocs.io/en/latest/installation.html) for more info.
**IMPORTANT:** DO NOT REMOVE EXISTING `eng.traineddata`, IT'S REQUIRED. **IMPORTANT:** DO NOT REMOVE EXISTING `eng.traineddata`, IT'S REQUIRED.
@@ -264,10 +264,10 @@ sudo systemctl restart stirlingpdf.service
Remember to set the necessary environment variables before running the project if you want to customize the application the list can be seen in the main readme. Remember to set the necessary environment variables before running the project if you want to customize the application the list can be seen in the main readme.
You can do this in the terminal by using the `export` command or -D arguements to java -jar command: You can do this in the terminal by using the `export` command or -D argument to java -jar command:
```bash ```bash
export APP_HOME_NAME="Stirling PDF" export APP_HOME_NAME="Stirling PDF"
or or
-DAPP_HOME_NAME="Stirling PDF" -DAPP_HOME_NAME="Stirling PDF"
``` ```

View File

@@ -1,13 +1,6 @@
# Pipeline Configuration and Usage Tutorial # Pipeline Configuration and Usage Tutorial
- Configure the pipeline config file and input files to run files against it
## Whilst Pipelines are in alpha... - For reuse, download the config file and re-upload it when needed, or place it in /pipeline/defaultWebUIConfigs/ to auto-load in the web UI for all users
You must enable this alpha functionality by setting
```yaml
system:
enableAlphaFunctionality: true
```
To true like in the above for your `/config/settings.yml` file, after restarting Stirling-PDF you should see both UI and folder scanning enabled.
## Steps to Configure and Use Your Pipeline ## Steps to Configure and Use Your Pipeline
@@ -40,3 +33,12 @@ To true like in the above for your `/config/settings.yml` file, after restarting
10. **Note on Web UI Limitations** 10. **Note on Web UI Limitations**
- The current web UI version does not support operations that require multiple different types of inputs, such as adding a separate image to a PDF. - The current web UI version does not support operations that require multiple different types of inputs, such as adding a separate image to a PDF.
### Current Limitations
- Cannot have more than one of the same operation
- Cannot input additional files via UI
- All files and operations run in serial mode

View File

@@ -6,7 +6,7 @@
[![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/) [![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/)
[![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf) [![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf)
[![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/paypalme/froodleplex) [![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/paypalme/froodleplex)
[![Github Sponser](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle) [![Github Sponsor](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle)
[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af) [![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
@@ -114,6 +114,7 @@ docker run -d \
-v /location/of/extraConfigs:/configs \ -v /location/of/extraConfigs:/configs \
-v /location/of/logs:/logs \ -v /location/of/logs:/logs \
-e DOCKER_ENABLE_SECURITY=false \ -e DOCKER_ENABLE_SECURITY=false \
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
--name stirling-pdf \ --name stirling-pdf \
frooodle/s-pdf:latest frooodle/s-pdf:latest
@@ -137,6 +138,7 @@ services:
# - /location/of/logs:/logs/ # - /location/of/logs:/logs/
environment: environment:
- DOCKER_ENABLE_SECURITY=false - DOCKER_ENABLE_SECURITY=false
- INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
``` ```
Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "podman". Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "podman".
@@ -172,7 +174,7 @@ Stirling PDF currently supports 26!
- Hindi (हिंदी) (hi_IN) - Hindi (हिंदी) (hi_IN)
- Hungarian (Magyar) (hu_HU) - Hungarian (Magyar) (hu_HU)
- Bulgarian (Български) (bg_BG) - Bulgarian (Български) (bg_BG)
- Sebian Latin alphabet (Srpski) (sr-Latn-RS) - Sebian Latin alphabet (Srpski) (sr_LATN_RS)
## Contributing (creating issues, translations, fixing bugs, etc.) ## Contributing (creating issues, translations, fixing bugs, etc.)
@@ -228,6 +230,7 @@ metrics:
- ``SYSTEM_ROOTURIPATH`` ie set to ``/pdf-app`` to Set the application's root URI to ``localhost:8080/pdf-app`` - ``SYSTEM_ROOTURIPATH`` ie set to ``/pdf-app`` to Set the application's root URI to ``localhost:8080/pdf-app``
- ``SYSTEM_CONNECTIONTIMEOUTMINUTES`` to set custom connection timeout values - ``SYSTEM_CONNECTIONTIMEOUTMINUTES`` to set custom connection timeout values
- ``DOCKER_ENABLE_SECURITY`` to tell docker to download security jar (required as true for auth login) - ``DOCKER_ENABLE_SECURITY`` to tell docker to download security jar (required as true for auth login)
- ``INSTALL_BOOK_AND_ADVANCED_HTML_OPS`` to download calibre onto stirling-pdf enabling pdf to/from book and advanced html conversion
## API ## API
For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation
@@ -262,7 +265,7 @@ For API usage you must provide a header with 'X-API-Key' and the associated API
- Redact text (Via UI not just automated way) - Redact text (Via UI not just automated way)
- Add Forms - Add Forms
- Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing - Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing
- Fill forms mannual and automatic - Fill forms manually or automatically
### Q2: Why is my application downloading .htm files? ### Q2: Why is my application downloading .htm files?
This is an issue caused commonly 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. This is an issue caused commonly 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.

View File

@@ -1,64 +1,64 @@
|Technology | Ultra-Lite | Lite | Full | |Technology | Ultra-Lite | Lite | Full |
|----------------|:----------:|:----:|:----:| |----------------|:----------:|:----:|:----:|
| Java | ✔️ | ✔️ | ✔️ | | Java | ✔️ | ✔️ | ✔️ |
| JavaScript | ✔️ | ✔️ | ✔️ | | JavaScript | ✔️ | ✔️ | ✔️ |
| Libre | | ✔️ | ✔️ | | Libre | | ✔️ | ✔️ |
| Python | | | ✔️ | | Python | | | ✔️ |
| OpenCV | | | ✔️ | | OpenCV | | | ✔️ |
| OCRmyPDF | | | ✔️ | | OCRmyPDF | | | ✔️ |
Operation | Ultra-Lite | Lite | Full Operation | Ultra-Lite | Lite | Full
--------------------|------------|------|----- --------------------|------------|------|-----
add-page-numbers | ✔️ | ✔️ | ✔️ add-page-numbers | ✔️ | ✔️ | ✔️
add-password | ✔️ | ✔️ | ✔️ add-password | ✔️ | ✔️ | ✔️
add-image | ✔️ | ✔️ | ✔️ add-image | ✔️ | ✔️ | ✔️
add-watermark | ✔️ | ✔️ | ✔️ add-watermark | ✔️ | ✔️ | ✔️
adjust-contrast | ✔️ | ✔️ | ✔️ adjust-contrast | ✔️ | ✔️ | ✔️
auto-split-pdf | ✔️ | ✔️ | ✔️ auto-split-pdf | ✔️ | ✔️ | ✔️
auto-redact | ✔️ | ✔️ | ✔️ auto-redact | ✔️ | ✔️ | ✔️
auto-rename | ✔️ | ✔️ | ✔️ auto-rename | ✔️ | ✔️ | ✔️
cert-sign | ✔️ | ✔️ | ✔️ cert-sign | ✔️ | ✔️ | ✔️
crop | ✔️ | ✔️ | ✔️ crop | ✔️ | ✔️ | ✔️
change-metadata | ✔️ | ✔️ | ✔️ change-metadata | ✔️ | ✔️ | ✔️
change-permissions | ✔️ | ✔️ | ✔️ change-permissions | ✔️ | ✔️ | ✔️
compare | ✔️ | ✔️ | ✔️ compare | ✔️ | ✔️ | ✔️
extract-page | ✔️ | ✔️ | ✔️ extract-page | ✔️ | ✔️ | ✔️
extract-images | ✔️ | ✔️ | ✔️ extract-images | ✔️ | ✔️ | ✔️
flatten | ✔️ | ✔️ | ✔️ flatten | ✔️ | ✔️ | ✔️
get-info-on-pdf | ✔️ | ✔️ | ✔️ get-info-on-pdf | ✔️ | ✔️ | ✔️
img-to-pdf | ✔️ | ✔️ | ✔️ img-to-pdf | ✔️ | ✔️ | ✔️
markdown-to-pdf | ✔️ | ✔️ | ✔️ markdown-to-pdf | ✔️ | ✔️ | ✔️
merge-pdfs | ✔️ | ✔️ | ✔️ merge-pdfs | ✔️ | ✔️ | ✔️
multi-page-layout | ✔️ | ✔️ | ✔️ multi-page-layout | ✔️ | ✔️ | ✔️
overlay-pdf | ✔️ | ✔️ | ✔️ overlay-pdf | ✔️ | ✔️ | ✔️
pdf-organizer | ✔️ | ✔️ | ✔️ pdf-organizer | ✔️ | ✔️ | ✔️
pdf-to-csv | ✔️ | ✔️ | ✔️ pdf-to-csv | ✔️ | ✔️ | ✔️
pdf-to-img | ✔️ | ✔️ | ✔️ pdf-to-img | ✔️ | ✔️ | ✔️
pdf-to-single-page | ✔️ | ✔️ | ✔️ pdf-to-single-page | ✔️ | ✔️ | ✔️
remove-pages | ✔️ | ✔️ | ✔️ remove-pages | ✔️ | ✔️ | ✔️
remove-password | ✔️ | ✔️ | ✔️ remove-password | ✔️ | ✔️ | ✔️
rotate-pdf | ✔️ | ✔️ | ✔️ rotate-pdf | ✔️ | ✔️ | ✔️
sanitize-pdf | ✔️ | ✔️ | ✔️ sanitize-pdf | ✔️ | ✔️ | ✔️
scale-pages | ✔️ | ✔️ | ✔️ scale-pages | ✔️ | ✔️ | ✔️
sign | ✔️ | ✔️ | ✔️ sign | ✔️ | ✔️ | ✔️
show-javascript | ✔️ | ✔️ | ✔️ show-javascript | ✔️ | ✔️ | ✔️
split-by-size-or-count | ✔️ | ✔️ | ✔️ split-by-size-or-count | ✔️ | ✔️ | ✔️
split-pdf-by-sections | ✔️ | ✔️ | ✔️ split-pdf-by-sections | ✔️ | ✔️ | ✔️
split-pdfs | ✔️ | ✔️ | ✔️ split-pdfs | ✔️ | ✔️ | ✔️
file-to-pdf | | ✔️ | ✔️ file-to-pdf | | ✔️ | ✔️
pdf-to-html | | ✔️ | ✔️ pdf-to-html | | ✔️ | ✔️
pdf-to-presentation | | ✔️ | ✔️ pdf-to-presentation | | ✔️ | ✔️
pdf-to-text | | ✔️ | ✔️ pdf-to-text | | ✔️ | ✔️
pdf-to-word | | ✔️ | ✔️ pdf-to-word | | ✔️ | ✔️
pdf-to-xml | | ✔️ | ✔️ pdf-to-xml | | ✔️ | ✔️
repair | | ✔️ | ✔️ repair | | ✔️ | ✔️
xlsx-to-pdf | | ✔️ | ✔️ xlsx-to-pdf | | ✔️ | ✔️
compress-pdf | | | ✔️ compress-pdf | | | ✔️
extract-image-scans | | | ✔️ extract-image-scans | | | ✔️
ocr-pdf | | | ✔️ ocr-pdf | | | ✔️
pdf-to-pdfa | | | ✔️ pdf-to-pdfa | | | ✔️
remove-blanks | | | ✔️ remove-blanks | | | ✔️

View File

@@ -1,6 +1,6 @@
plugins { plugins {
id 'java' id 'java'
id 'org.springframework.boot' version '3.2.2' id 'org.springframework.boot' version '3.2.3'
id 'io.spring.dependency-management' version '1.1.3' id 'io.spring.dependency-management' version '1.1.3'
id 'org.springdoc.openapi-gradle-plugin' version '1.8.0' id 'org.springdoc.openapi-gradle-plugin' version '1.8.0'
id "io.swagger.swaggerhub" version "1.3.2" id "io.swagger.swaggerhub" version "1.3.2"
@@ -12,7 +12,7 @@ plugins {
import com.github.jk1.license.render.* import com.github.jk1.license.render.*
group = 'stirling.software' group = 'stirling.software'
version = '0.21.0' version = '0.22.3'
sourceCompatibility = '17' sourceCompatibility = '17'
repositories { repositories {
@@ -20,7 +20,6 @@ repositories {
} }
licenseReport { licenseReport {
renderers = [new JsonReportRenderer()] renderers = [new JsonReportRenderer()]
} }
@@ -48,7 +47,6 @@ openApi {
outputFileName = "SwaggerDoc.json" outputFileName = "SwaggerDoc.json"
} }
launch4j { launch4j {
icon = "${projectDir}/src/main/resources/static/favicon.ico" icon = "${projectDir}/src/main/resources/static/favicon.ico"
@@ -87,26 +85,26 @@ spotless {
dependencies { dependencies {
//security updates //security updates
implementation 'ch.qos.logback:logback-classic:1.4.14' implementation 'ch.qos.logback:logback-classic:1.5.3'
implementation 'ch.qos.logback:logback-core:1.4.14' implementation 'ch.qos.logback:logback-core:1.5.3'
implementation 'org.springframework:spring-webmvc:6.1.2' implementation 'org.springframework:spring-webmvc:6.1.4'
implementation("io.github.pixee:java-security-toolkit:1.1.2") implementation("io.github.pixee:java-security-toolkit:1.1.2")
implementation 'org.yaml:snakeyaml:2.2' implementation 'org.yaml:snakeyaml:2.2'
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.2' implementation 'org.springframework.boot:spring-boot-starter-web:3.2.3'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.2' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.3'
if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') { if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.2' implementation 'org.springframework.boot:spring-boot-starter-security:3.2.3'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE' implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.2" implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.3"
//2.2.x requires rebuild of DB file.. need migration path //2.2.x requires rebuild of DB file.. need migration path
implementation "com.h2database:h2:2.1.214" implementation "com.h2database:h2:2.1.214"
} }
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.2.2' testImplementation 'org.springframework.boot:spring-boot-starter-test:3.2.3'
// Batik // Batik
implementation 'org.apache.xmlgraphics:batik-all:1.17' implementation 'org.apache.xmlgraphics:batik-all:1.17'
@@ -138,27 +136,29 @@ dependencies {
implementation ('com.opencsv:opencsv:5.9') { implementation ('com.opencsv:opencsv:5.9') {
exclude group: 'commons-logging', module: 'commons-logging' exclude group: 'commons-logging', module: 'commons-logging'
} }
implementation ('org.apache.pdfbox:pdfbox:3.0.1'){ implementation ('org.apache.pdfbox:pdfbox:3.0.1'){
exclude group: 'commons-logging', module: 'commons-logging' exclude group: 'commons-logging', module: 'commons-logging'
} }
implementation ('org.apache.pdfbox:xmpbox:3.0.1'){ implementation ('org.apache.pdfbox:xmpbox:3.0.1'){
exclude group: 'commons-logging', module: 'commons-logging' exclude group: 'commons-logging', module: 'commons-logging'
} }
implementation 'org.bouncycastle:bcprov-jdk18on:1.77' implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77' implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
implementation 'org.springframework.boot:spring-boot-starter-actuator:3.2.2' implementation 'org.springframework.boot:spring-boot-starter-actuator:3.2.3'
implementation 'io.micrometer:micrometer-core:1.12.2' implementation 'io.micrometer:micrometer-core:1.12.3'
implementation group: 'com.google.zxing', name: 'core', version: '3.5.2' implementation group: 'com.google.zxing', name: 'core', version: '3.5.3'
// https://mvnrepository.com/artifact/org.commonmark/commonmark // https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation 'org.commonmark:commonmark:0.21.0' implementation 'org.commonmark:commonmark:0.21.0'
implementation 'org.commonmark:commonmark-ext-gfm-tables:0.21.0' implementation 'org.commonmark:commonmark-ext-gfm-tables:0.21.0'
// https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core // https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0' implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'
developmentOnly("org.springframework.boot:spring-boot-devtools:3.2.2") implementation 'com.fathzer:javaluator:3.0.3'
developmentOnly("org.springframework.boot:spring-boot-devtools:3.2.3")
compileOnly 'org.projectlombok:lombok:1.18.30' compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.28' annotationProcessor 'org.projectlombok:lombok:1.18.28'
} }

View File

@@ -1,5 +1,5 @@
apiVersion: v2 apiVersion: v2
appVersion: 0.14.2 appVersion: 0.22.3
description: locally hosted web application that allows you to perform various operations on PDF files description: locally hosted web application that allows you to perform various operations on PDF files
home: https://github.com/Stirling-Tools/Stirling-PDF home: https://github.com/Stirling-Tools/Stirling-PDF
keywords: keywords:

View File

@@ -43,6 +43,6 @@ spec:
name: http name: http
{{- end }} {{- end }}
protocol: TCP protocol: TCP
selector: selector:
{{- include "stirlingpdf.selectorLabels" . | nindent 4 }} {{- include "stirlingpdf.selectorLabels" . | nindent 4 }}

View File

@@ -16,11 +16,11 @@ commonLabels: {}
# team_name: dev # team_name: dev
envs: [] envs: []
# - name: PP_HOME_NAME # - name: UI_APP_NAME
# value: "Stirling PDF" # value: "Stirling PDF"
# - name: APP_HOME_DESCRIPTION # - name: UI_HOME_DESCRIPTION
# value: "Your locally hosted one-stop-shop for all your PDF needs." # value: "Your locally hosted one-stop-shop for all your PDF needs."
# - name: APP_NAVBAR_NAME # - name: UI_APP_NAVBAR_NAME
# value: "Stirling PDF" # value: "Stirling PDF"
# - name: ALLOW_GOOGLE_VISIBILITY # - name: ALLOW_GOOGLE_VISIBILITY
# value: "true" # value: "true"

View File

@@ -19,8 +19,8 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs173"> id="defs173">
<linearGradient <linearGradient
id="XMLID_5_" id="XMLID_5_"
gradientUnits="userSpaceOnUse" gradientUnits="userSpaceOnUse"
@@ -37,7 +37,7 @@
style="stop-color:#C2C2C9" style="stop-color:#C2C2C9"
id="stop158" /> id="stop158" />
</linearGradient> </linearGradient>
</defs><sodipodi:namedview </defs><sodipodi:namedview
id="namedview171" id="namedview171"
pagecolor="#ffffff" pagecolor="#ffffff"

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -15,7 +15,7 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:

View File

@@ -15,12 +15,15 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:
DOCKER_ENABLE_SECURITY: "true" DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "true" SECURITY_ENABLELOGIN: "true"
PUID: 1002
PGID: 1002
UMASK: "022"
SYSTEM_DEFAULTLOCALE: en-US SYSTEM_DEFAULTLOCALE: en-US
UI_APPNAME: Stirling-PDF UI_APPNAME: Stirling-PDF
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security

View File

@@ -15,7 +15,7 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:

View File

@@ -15,7 +15,7 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:

182
gradlew.bat vendored
View File

@@ -1,91 +1,91 @@
@rem @rem
@rem Copyright 2015 the original author or authors. @rem Copyright 2015 the original author or authors.
@rem @rem
@rem Licensed under the Apache License, Version 2.0 (the "License"); @rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License. @rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at @rem You may obtain a copy of the License at
@rem @rem
@rem https://www.apache.org/licenses/LICENSE-2.0 @rem https://www.apache.org/licenses/LICENSE-2.0
@rem @rem
@rem Unless required by applicable law or agreed to in writing, software @rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS, @rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@rem @rem
@rem ########################################################################## @rem ##########################################################################
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter. @rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:findJavaFromJavaHome :findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL% set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE% exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal
:omega :omega

View File

@@ -6,7 +6,8 @@
"parameters": { "parameters": {
"horizontalDivisions": 2, "horizontalDivisions": 2,
"verticalDivisions": 2, "verticalDivisions": 2,
"fileInput": "automated" "fileInput": "automated",
"merge": false
} }
}, },
{ {
@@ -30,4 +31,4 @@
}, },
"outputDir": "{outputFolder}", "outputDir": "{outputFolder}",
"outputFileName": "{filename}" "outputFileName": "{filename}"
} }

View File

@@ -1,37 +0,0 @@
import cv2
import sys
import argparse
import numpy as np
def is_blank_image(image_path, threshold=10, white_percent=99, white_value=255, blur_size=5):
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if image is None:
print(f"Error: Unable to read the image file: {image_path}")
return False
# Apply Gaussian blur to reduce noise
blurred_image = cv2.GaussianBlur(image, (blur_size, blur_size), 0)
_, thresholded_image = cv2.threshold(blurred_image, white_value - threshold, white_value, cv2.THRESH_BINARY)
# Calculate the percentage of white pixels in the thresholded image
white_pixels = np.sum(thresholded_image == white_value)
white_pixel_percentage = (white_pixels / thresholded_image.size) * 100
print(f"Page has white pixel percent of {white_pixel_percentage}")
return white_pixel_percentage >= white_percent
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Detect if an image is considered blank or not.')
parser.add_argument('image_path', help='The path to the image file.')
parser.add_argument('-t', '--threshold', type=int, default=10, help='Threshold for determining white pixels. The default value is 10.')
parser.add_argument('-w', '--white_percent', type=float, default=99, help='The percentage of white pixels for an image to be considered blank. The default value is 99.')
args = parser.parse_args()
blank = is_blank_image(args.image_path, args.threshold, args.white_percent)
# Return code 1: The image is considered blank.
# Return code 0: The image is not considered blank.
sys.exit(int(blank))

View File

@@ -4,7 +4,7 @@ if [ "$DOCKER_ENABLE_SECURITY" = "true" ] && [ "$VERSION_TAG" != "alpha" ]; then
if [ ! -f app-security.jar ]; then if [ ! -f app-security.jar ]; then
echo "Trying to download from: https://github.com/Stirling-Tools/Stirling-PDF/releases/download/v$VERSION_TAG/Stirling-PDF-with-login.jar" echo "Trying to download from: https://github.com/Stirling-Tools/Stirling-PDF/releases/download/v$VERSION_TAG/Stirling-PDF-with-login.jar"
curl -L -o app-security.jar https://github.com/Stirling-Tools/Stirling-PDF/releases/download/v$VERSION_TAG/Stirling-PDF-with-login.jar curl -L -o app-security.jar https://github.com/Stirling-Tools/Stirling-PDF/releases/download/v$VERSION_TAG/Stirling-PDF-with-login.jar
# If the first download attempt failed, try with the 'v' prefix # If the first download attempt failed, try with the 'v' prefix
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Trying to download from: https://github.com/Stirling-Tools/Stirling-PDF/releases/download/$VERSION_TAG/Stirling-PDF-with-login.jar" echo "Trying to download from: https://github.com/Stirling-Tools/Stirling-PDF/releases/download/$VERSION_TAG/Stirling-PDF-with-login.jar"
@@ -14,6 +14,8 @@ if [ "$DOCKER_ENABLE_SECURITY" = "true" ] && [ "$VERSION_TAG" != "alpha" ]; then
if [ $? -eq 0 ]; then # checks if curl was successful if [ $? -eq 0 ]; then # checks if curl was successful
rm -f app.jar rm -f app.jar
ln -s app-security.jar app.jar ln -s app-security.jar app.jar
chown stirlingpdfuser:stirlingpdfgroup app.jar || true
chmod 755 app.jar || true
fi fi
fi fi
fi fi

View File

@@ -1,6 +1,29 @@
#!/bin/sh #!/bin/sh
# Update the user and group IDs as per environment variables
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
usermod -o -u "$PUID" stirlingpdfuser || true
fi
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
groupmod -o -g "$PGID" stirlingpdfgroup || true
fi
umask "$UMASK" || true
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
apk add --no-cache calibre@testing
fi
/scripts/download-security-jar.sh /scripts/download-security-jar.sh
# Run the main command echo "Setting permissions and ownership for necessary directories..."
exec "$@" if chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar; then
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
# If chown succeeds, execute the command as stirlingpdfuser
exec su-exec stirlingpdfuser "$@"
else
# If chown fails, execute the command without changing the user context
echo "[WARN] Chown failed, running as host user"
exec "$@"
fi

View File

@@ -13,18 +13,47 @@ if [ -d /usr/share/tesseract-ocr/5/tessdata ]; then
cp -r /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata || true; cp -r /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata || true;
fi fi
# Update the user and group IDs as per environment variables
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
usermod -o -u "$PUID" stirlingpdfuser || true
fi
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
groupmod -o -g "$PGID" stirlingpdfgroup || true
fi
umask "$UMASK" || true
# Check if TESSERACT_LANGS environment variable is set and is not empty # Check if TESSERACT_LANGS environment variable is set and is not empty
if [[ -n "$TESSERACT_LANGS" ]]; then if [[ -n "$TESSERACT_LANGS" ]]; then
# Convert comma-separated values to a space-separated list # Convert comma-separated values to a space-separated list
LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ') LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ')
pattern='^[a-zA-Z]{2,4}(_[a-zA-Z]{2,4})?$'
# Install each language pack # Install each language pack
for LANG in $LANGS; do for LANG in $LANGS; do
apt-get install -y "tesseract-ocr-$LANG" if [[ $LANG =~ $pattern ]]; then
apk add --no-cache "tesseract-ocr-data-$LANG"
else
echo "Skipping invalid language code"
fi
done done
fi fi
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
apk add --no-cache calibre@testing
fi
/scripts/download-security-jar.sh /scripts/download-security-jar.sh
# Run the main command echo "Setting permissions and ownership for necessary directories..."
exec "$@" # Attempt to change ownership of directories and files
if chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar; then
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
# If chown succeeds, execute the command as stirlingpdfuser
exec su-exec stirlingpdfuser "$@"
else
# If chown fails, execute the command without changing the user context
echo "[WARN] Chown failed, running as host user"
exec "$@"
fi

View File

@@ -2,7 +2,7 @@ import argparse
import sys import sys
import cv2 import cv2
import numpy as np import numpy as np
import os import os
def find_photo_boundaries(image, background_color, tolerance=30, min_area=10000, min_contour_area=500): def find_photo_boundaries(image, background_color, tolerance=30, min_area=10000, min_contour_area=500):
mask = cv2.inRange(image, background_color - tolerance, background_color + tolerance) mask = cv2.inRange(image, background_color - tolerance, background_color + tolerance)
@@ -49,9 +49,9 @@ def auto_rotate(image, angle_threshold=1):
angles = [] angles = []
for rho, theta in lines[:, 0]: for rho, theta in lines[:, 0]:
angles.append((theta * 180) / np.pi - 90) angles.append((theta * 180) / np.pi - 90)
angle = np.median(angles) angle = np.median(angles)
if abs(angle) < angle_threshold: if abs(angle) < angle_threshold:
return image return image
@@ -65,16 +65,16 @@ def auto_rotate(image, angle_threshold=1):
def crop_borders(image, border_color, tolerance=30): def crop_borders(image, border_color, tolerance=30):
mask = cv2.inRange(image, border_color - tolerance, border_color + tolerance) mask = cv2.inRange(image, border_color - tolerance, border_color + tolerance)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) == 0: if len(contours) == 0:
return image return image
largest_contour = max(contours, key=cv2.contourArea) largest_contour = max(contours, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(largest_contour) x, y, w, h = cv2.boundingRect(largest_contour)
return image[y:y+h, x:x+w] return image[y:y+h, x:x+w]
def split_photos(input_file, output_directory, tolerance=30, min_area=10000, min_contour_area=500, angle_threshold=10, border_size=0): def split_photos(input_file, output_directory, tolerance=30, min_area=10000, min_contour_area=500, angle_threshold=10, border_size=0):
image = cv2.imread(input_file) image = cv2.imread(input_file)
background_color = estimate_background_color(image) background_color = estimate_background_color(image)
@@ -110,7 +110,7 @@ if __name__ == "__main__":
parser.add_argument("--min_contour_area", type=int, default=500, help="Sets the minimum contour area threshold for a photo (default: 500).") parser.add_argument("--min_contour_area", type=int, default=500, help="Sets the minimum contour area threshold for a photo (default: 500).")
parser.add_argument("--angle_threshold", type=int, default=10, help="Sets the minimum absolute angle required for the image to be rotated (default: 10).") parser.add_argument("--angle_threshold", type=int, default=10, help="Sets the minimum absolute angle required for the image to be rotated (default: 10).")
parser.add_argument("--border_size", type=int, default=0, help="Sets the size of the border added and removed to prevent white borders in the output (default: 0).") parser.add_argument("--border_size", type=int, default=0, help="Sets the size of the border added and removed to prevent white borders in the output (default: 0).")
args = parser.parse_args() args = parser.parse_args()
split_photos(args.input_file, args.output_directory, tolerance=args.tolerance, min_area=args.min_area, min_contour_area=args.min_contour_area, angle_threshold=args.angle_threshold, border_size=args.border_size) split_photos(args.input_file, args.output_directory, tolerance=args.tolerance, min_area=args.min_area, min_contour_area=args.min_contour_area, angle_threshold=args.angle_threshold, border_size=args.border_size)

View File

@@ -1,10 +1,15 @@
package stirling.software.SPDF; package stirling.software.SPDF;
import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Collections; import java.util.Collections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
@@ -14,14 +19,25 @@ import io.github.pixee.security.SystemCommand;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import stirling.software.SPDF.config.ConfigInitializer; import stirling.software.SPDF.config.ConfigInitializer;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.model.ApplicationProperties;
@SpringBootApplication @SpringBootApplication
@EnableScheduling @EnableScheduling
public class SPdfApplication { public class SPdfApplication {
private static final Logger logger = LoggerFactory.getLogger(SPdfApplication.class);
@Autowired private Environment env; @Autowired private Environment env;
@Autowired ApplicationProperties applicationProperties;
private static String serverPortStatic;
@Value("${server.port:8080}")
public void setServerPortStatic(String port) {
SPdfApplication.serverPortStatic = port;
}
@PostConstruct @PostConstruct
public void init() { public void init() {
// Check if the BROWSER_OPEN environment variable is set to true // Check if the BROWSER_OPEN environment variable is set to true
@@ -30,7 +46,7 @@ public class SPdfApplication {
if (browserOpen) { if (browserOpen) {
try { try {
String url = "http://localhost:" + getPort(); String url = "http://localhost:" + getNonStaticPort();
String os = System.getProperty("os.name").toLowerCase(); String os = System.getProperty("os.name").toLowerCase();
Runtime rt = Runtime.getRuntime(); Runtime rt = Runtime.getRuntime();
@@ -39,12 +55,13 @@ public class SPdfApplication {
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url); SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("Error opening browser: {}", e.getMessage());
} }
} }
logger.info("Running configs {}", applicationProperties.toString());
} }
public static void main(String[] args) { public static void main(String[] args) throws IOException, InterruptedException {
SpringApplication app = new SpringApplication(SPdfApplication.class); SpringApplication app = new SpringApplication(SPdfApplication.class);
app.addInitializers(new ConfigInitializer()); app.addInitializers(new ConfigInitializer());
if (Files.exists(Paths.get("configs/settings.yml"))) { if (Files.exists(Paths.get("configs/settings.yml"))) {
@@ -52,7 +69,7 @@ public class SPdfApplication {
Collections.singletonMap( Collections.singletonMap(
"spring.config.additional-location", "file:configs/settings.yml")); "spring.config.additional-location", "file:configs/settings.yml"));
} else { } else {
System.out.println( logger.warn(
"External configuration file 'configs/settings.yml' does not exist. Using default configuration and environment configuration instead."); "External configuration file 'configs/settings.yml' does not exist. Using default configuration and environment configuration instead.");
} }
app.run(args); app.run(args);
@@ -60,24 +77,30 @@ public class SPdfApplication {
try { try {
Thread.sleep(1000); Thread.sleep(1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// TODO Auto-generated catch block Thread.currentThread().interrupt();
e.printStackTrace(); throw new RuntimeException("Thread interrupted while sleeping", e);
} }
GeneralUtils.createDir("customFiles/static/"); try {
GeneralUtils.createDir("customFiles/templates/"); Files.createDirectories(Path.of("customFiles/static/"));
Files.createDirectories(Path.of("customFiles/templates/"));
System.out.println("Stirling-PDF Started."); } catch (Exception e) {
logger.error("Error creating directories: {}", e.getMessage());
String url = "http://localhost:" + getPort(); }
System.out.println("Navigate to " + url); printStartupLogs();
} }
public static String getPort() { private static void printStartupLogs() {
String port = System.getProperty("local.server.port"); logger.info("Stirling-PDF Started.");
if (port == null || port.isEmpty()) { String url = "http://localhost:" + getStaticPort();
port = "8080"; logger.info("Navigate to {}", url);
} }
return port;
public static String getStaticPort() {
return serverPortStatic;
}
public String getNonStaticPort() {
return serverPortStatic;
} }
} }

View File

@@ -79,9 +79,10 @@ public class AppConfig {
@Bean(name = "bookAndHtmlFormatsInstalled") @Bean(name = "bookAndHtmlFormatsInstalled")
public boolean bookAndHtmlFormatsInstalled() { public boolean bookAndHtmlFormatsInstalled() {
return applicationProperties String installOps = System.getProperty("INSTALL_BOOK_AND_ADVANCED_HTML_OPS");
.getSystem() if (installOps == null) {
.getCustomApplications() installOps = System.getenv("INSTALL_BOOK_AND_ADVANCED_HTML_OPS");
.isInstallBookAndHtmlFormats(); }
return "true".equalsIgnoreCase(installOps);
} }
} }

View File

@@ -79,6 +79,16 @@ public class ConfigInitializer
return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : ""; return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : "";
}; };
Function<String, Integer> getIndentationLevel =
line -> {
int count = 0;
for (char ch : line.toCharArray()) {
if (ch == ' ') count++;
else break;
}
return count;
};
Set<String> userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet()); Set<String> userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet());
for (String line : templateLines) { for (String line : templateLines) {
@@ -134,10 +144,77 @@ public class ConfigInitializer
.map(extractKey) .map(extractKey)
.anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey)); .anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey));
if (!isPresentInTemplate && !isCommented.apply(userLine)) { if (!isPresentInTemplate && !isCommented.apply(userLine)) {
mergedLines.add(userLine); if (!childOfTemplateEntry(
isCommented,
extractKey,
getIndentationLevel,
userLines,
userLine,
templateLines)) {
// check if userLine is a child of a entry within templateLines or not, if child
// of parent in templateLines then dont add to mergedLines, if anything else
// then add
mergedLines.add(userLine);
}
} }
} }
Files.write(outputPath, mergedLines, StandardCharsets.UTF_8); Files.write(outputPath, mergedLines, StandardCharsets.UTF_8);
} }
// New method to check if a userLine is a child of an entry in templateLines
boolean childOfTemplateEntry(
Function<String, Boolean> isCommented,
Function<String, String> extractKey,
Function<String, Integer> getIndentationLevel,
List<String> userLines,
String userLine,
List<String> templateLines) {
String userKey = extractKey.apply(userLine).trim();
int userIndentation = getIndentationLevel.apply(userLine);
// Start by assuming the line is not a child of an entry in templateLines
boolean isChild = false;
// Iterate backwards through userLines from the current line to find any parent
for (int i = userLines.indexOf(userLine) - 1; i >= 0; i--) {
String potentialParentLine = userLines.get(i);
int parentIndentation = getIndentationLevel.apply(potentialParentLine);
// Check if we've reached a potential parent based on indentation
if (parentIndentation < userIndentation) {
String parentKey = extractKey.apply(potentialParentLine).trim();
// Now, check if this potential parent or any of its parents exist in templateLines
boolean parentExistsInTemplate =
templateLines.stream()
.filter(line -> !isCommented.apply(line)) // Skip commented lines
.anyMatch(
templateLine -> {
String templateKey =
extractKey.apply(templateLine).trim();
return parentKey.equalsIgnoreCase(templateKey);
});
if (!parentExistsInTemplate) {
// If the parent does not exist in template, check the next level parent
userIndentation =
parentIndentation; // Update userIndentation to the parent's indentation
// for next iteration
if (parentIndentation == 0) {
// If we've reached the top-level parent and it's not in template, the
// original line is considered not a child
isChild = false;
break;
}
} else {
// If any parent exists in template, the original line is considered a child
isChild = true;
break;
}
}
}
return isChild; // Return true if the line is not a child of any entry in templateLines
}
} }

View File

@@ -140,7 +140,6 @@ public class EndpointConfiguration {
// CLI // CLI
addEndpointToGroup("CLI", "compress-pdf"); addEndpointToGroup("CLI", "compress-pdf");
addEndpointToGroup("CLI", "extract-image-scans"); addEndpointToGroup("CLI", "extract-image-scans");
addEndpointToGroup("CLI", "remove-blanks");
addEndpointToGroup("CLI", "repair"); addEndpointToGroup("CLI", "repair");
addEndpointToGroup("CLI", "pdf-to-pdfa"); addEndpointToGroup("CLI", "pdf-to-pdfa");
addEndpointToGroup("CLI", "file-to-pdf"); addEndpointToGroup("CLI", "file-to-pdf");
@@ -218,6 +217,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "split-by-size-or-count"); addEndpointToGroup("Java", "split-by-size-or-count");
addEndpointToGroup("Java", "overlay-pdf"); addEndpointToGroup("Java", "overlay-pdf");
addEndpointToGroup("Java", "split-pdf-by-sections"); addEndpointToGroup("Java", "split-pdf-by-sections");
addEndpointToGroup("Java", "remove-blanks");
// Javascript // Javascript
addEndpointToGroup("Javascript", "pdf-organizer"); addEndpointToGroup("Javascript", "pdf-organizer");

View File

@@ -1,69 +0,0 @@
package stirling.software.SPDF.config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
@Component
public class PostStartupProcesses {
@Autowired ApplicationProperties applicationProperties;
@Autowired
@Qualifier("RunningInDocker")
private boolean runningInDocker;
@Autowired
@Qualifier("bookAndHtmlFormatsInstalled")
private boolean bookAndHtmlFormatsInstalled;
private static final Logger logger = LoggerFactory.getLogger(PostStartupProcesses.class);
@PostConstruct
public void runInstallCommandBasedOnEnvironment() throws IOException, InterruptedException {
List<List<String>> commands = new ArrayList<>();
// Checking for DOCKER_INSTALL_BOOK_FORMATS environment variable
if (bookAndHtmlFormatsInstalled) {
List<String> tmpList = new ArrayList<>();
tmpList = new ArrayList<>();
tmpList.addAll(Arrays.asList("apk add --no-cache calibre"));
commands.add(tmpList);
}
if (!commands.isEmpty()) {
// Run the command
if (runningInDocker) {
List<String> tmpList = new ArrayList<>();
for (List<String> list : commands) {
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.INSTALL_APP, true)
.runCommandWithOutputHandling(list);
logger.info("RC for app installs {}", returnCode.getRc());
}
} else {
logger.info(
"Not running inside Docker so skipping automated install process with command.");
}
} else {
if (runningInDocker) {
logger.info("No custom apps to install.");
}
}
}
}

View File

@@ -1,6 +1,7 @@
package stirling.software.SPDF.config.security; package stirling.software.SPDF.config.security;
import java.io.IOException; import java.io.IOException;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
@@ -12,15 +13,19 @@ import org.springframework.stereotype.Component;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.model.User;
@Component @Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Autowired private final LoginAttemptService loginAttemptService; @Autowired private final LoginAttemptService loginAttemptService;
@Autowired @Autowired private final UserService userService; // Inject the UserService
public CustomAuthenticationFailureHandler(LoginAttemptService loginAttemptService) {
public CustomAuthenticationFailureHandler(
LoginAttemptService loginAttemptService, UserService userService) {
this.loginAttemptService = loginAttemptService; this.loginAttemptService = loginAttemptService;
this.userService = userService;
} }
@Override @Override
@@ -33,17 +38,27 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
logger.error("Failed login attempt from IP: " + ip); logger.error("Failed login attempt from IP: " + ip);
String username = request.getParameter("username"); String username = request.getParameter("username");
if (loginAttemptService.loginAttemptCheck(username)) { if (!isDemoUser(username)) {
setDefaultFailureUrl("/login?error=locked"); if (loginAttemptService.loginAttemptCheck(username)) {
} else {
if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
setDefaultFailureUrl("/login?error=badcredentials");
} else if (exception.getClass().isAssignableFrom(LockedException.class)) {
setDefaultFailureUrl("/login?error=locked"); setDefaultFailureUrl("/login?error=locked");
} else {
if (exception.getClass().isAssignableFrom(LockedException.class)) {
setDefaultFailureUrl("/login?error=locked");
}
} }
} }
if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
setDefaultFailureUrl("/login?error=badcredentials");
}
super.onAuthenticationFailure(request, response, exception); super.onAuthenticationFailure(request, response, exception);
} }
private boolean isDemoUser(String username) {
Optional<User> user = userService.findByUsername(username);
return user.isPresent()
&& user.get().getAuthorities().stream()
.anyMatch(authority -> "ROLE_DEMO_USER".equals(authority.getAuthority()));
}
} }

View File

@@ -9,6 +9,9 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@@ -18,6 +21,7 @@ import org.springframework.security.web.authentication.rememberme.PersistentToke
import org.springframework.security.web.savedrequest.NullRequestCache; import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.repository.JPATokenRepositoryImpl; import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
@Configuration @Configuration
@@ -44,6 +48,11 @@ public class SecurityConfiguration {
@Autowired private FirstLoginFilter firstLoginFilter; @Autowired private FirstLoginFilter firstLoginFilter;
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
@@ -53,6 +62,15 @@ public class SecurityConfiguration {
http.csrf(csrf -> csrf.disable()); http.csrf(csrf -> csrf.disable());
http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class); http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class);
http.sessionManagement(
sessionManagement ->
sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(10)
.maxSessionsPreventsLogin(false)
.sessionRegistry(sessionRegistry())
.expiredUrl("/login?logout=true"));
http.formLogin( http.formLogin(
formLogin -> formLogin ->
formLogin formLogin
@@ -62,7 +80,7 @@ public class SecurityConfiguration {
.defaultSuccessUrl("/") .defaultSuccessUrl("/")
.failureHandler( .failureHandler(
new CustomAuthenticationFailureHandler( new CustomAuthenticationFailureHandler(
loginAttemptService)) loginAttemptService, userService))
.permitAll()) .permitAll())
.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache())) .requestCache(requestCache -> requestCache.requestCache(new NullRequestCache()))
.logout( .logout(
@@ -71,7 +89,18 @@ public class SecurityConfiguration {
new AntPathRequestMatcher("/logout")) new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout=true") .logoutSuccessUrl("/login?logout=true")
.invalidateHttpSession(true) // Invalidate session .invalidateHttpSession(true) // Invalidate session
.deleteCookies("JSESSIONID", "remember-me")) .deleteCookies("JSESSIONID", "remember-me")
.addLogoutHandler(
(request, response, authentication) -> {
HttpSession session =
request.getSession(false);
if (session != null) {
String sessionId = session.getId();
sessionRegistry()
.removeSessionInformation(
sessionId);
}
}))
.rememberMe( .rememberMe(
rememberMeConfigurer -> rememberMeConfigurer ->
rememberMeConfigurer // Use the configurator directly rememberMeConfigurer // Use the configurator directly

View File

@@ -82,7 +82,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter() response.getWriter()
.write( .write(
"Authentication required. Please provide a X-API-KEY in request header.\nThis is found in Settings -> Account Settings -> API Key\nAlternativly you can disable authentication if this is unexpected"); "Authentication required. Please provide a X-API-KEY in request header.\nThis is found in Settings -> Account Settings -> API Key\nAlternatively you can disable authentication if this is unexpected");
return; return;
} }
} }

View File

@@ -176,6 +176,10 @@ public class UserService implements UserServiceInterface {
return userRepository.findByUsername(username); return userRepository.findByUsername(username);
} }
public Optional<User> findByUsernameIgnoreCase(String username) {
return userRepository.findByUsernameIgnoreCase(username);
}
public void changeUsername(User user, String newUsername) { public void changeUsername(User user, String newUsername) {
user.setUsername(newUsername); user.setUsername(newUsername);
userRepository.save(user); userRepository.save(user);
@@ -194,4 +198,8 @@ public class UserService implements UserServiceInterface {
public boolean isPasswordCorrect(User user, String currentPassword) { public boolean isPasswordCorrect(User user, String currentPassword) {
return passwordEncoder.matches(currentPassword, user.getPassword()); return passwordEncoder.matches(currentPassword, user.getPassword());
} }
public boolean isUsernameValid(String username) {
return username.matches("[a-zA-Z0-9]+");
}
} }

View File

@@ -38,7 +38,7 @@ public class MergeController {
private static final Logger logger = LoggerFactory.getLogger(MergeController.class); private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
private PDDocument mergeDocuments(List<PDDocument> documents) throws IOException { public PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
PDDocument mergedDoc = new PDDocument(); PDDocument mergedDoc = new PDDocument();
for (PDDocument doc : documents) { for (PDDocument doc : documents) {
for (PDPage page : doc.getPages()) { for (PDPage page : doc.getPages()) {

View File

@@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.api;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
@@ -50,7 +51,9 @@ public class RearrangePagesPDFController {
String[] pageOrderArr = pagesToDelete.split(","); String[] pageOrderArr = pagesToDelete.split(",");
List<Integer> pagesToRemove = List<Integer> pagesToRemove =
GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages()); GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages(), false);
Collections.sort(pagesToRemove);
for (int i = pagesToRemove.size() - 1; i >= 0; i--) { for (int i = pagesToRemove.size() - 1; i >= 0; i--) {
int pageIndex = pagesToRemove.get(i); int pageIndex = pagesToRemove.get(i);
@@ -192,7 +195,7 @@ public class RearrangePagesPDFController {
if (sortType != null && sortType.length() > 0) { if (sortType != null && sortType.length() > 0) {
newPageOrder = processSortTypes(sortType, totalPages); newPageOrder = processSortTypes(sortType, totalPages);
} else { } else {
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages); newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, false);
} }
logger.info("newPageOrder = " + newPageOrder); logger.info("newPageOrder = " + newPageOrder);
logger.info("totalPages = " + totalPages); logger.info("totalPages = " + totalPages);

View File

@@ -49,10 +49,16 @@ public class SplitPDFController {
// open the pdf document // open the pdf document
PDDocument document = Loader.loadPDF(file.getBytes()); PDDocument document = Loader.loadPDF(file.getBytes());
int totalPages = document.getNumberOfPages();
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
System.out.println(
pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
if (!pageNumbers.contains(totalPages - 1)) {
// Create a mutable ArrayList so we can add to it
pageNumbers = new ArrayList<>(pageNumbers);
pageNumbers.add(totalPages - 1);
}
List<Integer> pageNumbers = request.getPageNumbersList(document, true);
if (!pageNumbers.contains(document.getNumberOfPages() - 1))
pageNumbers.add(document.getNumberOfPages() - 1);
logger.info( logger.info(
"Splitting PDF into pages: {}", "Splitting PDF into pages: {}",
pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(","))); pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
@@ -65,7 +71,7 @@ public class SplitPDFController {
for (int i = previousPageNumber; i <= splitPoint; i++) { for (int i = previousPageNumber; i <= splitPoint; i++) {
PDPage page = document.getPage(i); PDPage page = document.getPage(i);
splitDocument.addPage(page); splitDocument.addPage(page);
logger.debug("Adding page {} to split document", i); logger.info("Adding page {} to split document", i);
} }
previousPageNumber = splitPoint + 1; previousPageNumber = splitPoint + 1;

View File

@@ -53,8 +53,21 @@ public class SplitPdfBySectionsController {
// Process the PDF based on split parameters // Process the PDF based on split parameters
int horiz = request.getHorizontalDivisions() + 1; int horiz = request.getHorizontalDivisions() + 1;
int verti = request.getVerticalDivisions() + 1; int verti = request.getVerticalDivisions() + 1;
boolean merge = request.isMerge();
List<PDDocument> splitDocuments = splitPdfPages(sourceDocument, verti, horiz); List<PDDocument> splitDocuments = splitPdfPages(sourceDocument, verti, horiz);
String filename =
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
if (merge) {
MergeController mergeController = new MergeController();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mergeController.mergeDocuments(splitDocuments).save(baos);
return WebResponseUtils.bytesToWebResponse(
baos.toByteArray(),
filename + "_split.pdf",
MediaType.APPLICATION_OCTET_STREAM);
}
for (PDDocument doc : splitDocuments) { for (PDDocument doc : splitDocuments) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.save(baos); doc.save(baos);
@@ -65,9 +78,6 @@ public class SplitPdfBySectionsController {
sourceDocument.close(); sourceDocument.close();
Path zipFile = Files.createTempFile("split_documents", ".zip"); Path zipFile = Files.createTempFile("split_documents", ".zip");
String filename =
Filenames.toSimpleFileName(file.getOriginalFilename())
.replaceFirst("[.][^.]+$", "");
byte[] data; byte[] data;
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) { try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {

View File

@@ -10,6 +10,9 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@@ -28,7 +31,6 @@ import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.Role; import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.api.user.UpdateUserDetails;
import stirling.software.SPDF.model.api.user.UsernameAndPass; import stirling.software.SPDF.model.api.user.UsernameAndPass;
@Controller @Controller
@@ -50,67 +52,25 @@ public class UserController {
return "redirect:/login?registered=true"; return "redirect:/login?registered=true";
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/change-username-and-password")
public RedirectView changeUsernameAndPassword(
Principal principal,
@ModelAttribute UpdateUserDetails requestModel,
HttpServletRequest request,
HttpServletResponse response,
RedirectAttributes redirectAttributes) {
String currentPassword = requestModel.getPassword();
String newPassword = requestModel.getNewPassword();
String newUsername = requestModel.getNewUsername();
if (principal == null) {
return new RedirectView("/change-creds?messageType=notAuthenticated");
}
Optional<User> userOpt = userService.findByUsername(principal.getName());
if (userOpt == null || userOpt.isEmpty()) {
return new RedirectView("/change-creds?messageType=userNotFound");
}
User user = userOpt.get();
if (!userService.isPasswordCorrect(user, currentPassword)) {
return new RedirectView("/change-creds?messageType=incorrectPassword");
}
if (!user.getUsername().equals(newUsername) && userService.usernameExists(newUsername)) {
return new RedirectView("/change-creds?messageType=usernameExists");
}
userService.changePassword(user, newPassword);
if (newUsername != null
&& newUsername.length() > 0
&& !user.getUsername().equals(newUsername)) {
userService.changeUsername(user, newUsername);
}
userService.changeFirstUse(user, false);
// Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null);
return new RedirectView("/login?messageType=credsUpdated");
}
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/change-username") @PostMapping("/change-username")
public RedirectView changeUsername( public RedirectView changeUsername(
Principal principal, Principal principal,
@RequestParam String currentPassword, @RequestParam(name = "currentPassword") String currentPassword,
@RequestParam String newUsername, @RequestParam(name = "newUsername") String newUsername,
HttpServletRequest request, HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
RedirectAttributes redirectAttributes) { RedirectAttributes redirectAttributes) {
if (!userService.isUsernameValid(newUsername)) {
return new RedirectView("/account?messageType=invalidUsername");
}
if (principal == null) { if (principal == null) {
return new RedirectView("/account?messageType=notAuthenticated"); return new RedirectView("/account?messageType=notAuthenticated");
} }
Optional<User> userOpt = userService.findByUsername(principal.getName()); Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName());
if (userOpt == null || userOpt.isEmpty()) { if (userOpt == null || userOpt.isEmpty()) {
return new RedirectView("/account?messageType=userNotFound"); return new RedirectView("/account?messageType=userNotFound");
@@ -118,6 +78,10 @@ public class UserController {
User user = userOpt.get(); User user = userOpt.get();
if (user.getUsername().equals(newUsername)) {
return new RedirectView("/account?messageType=usernameExists");
}
if (!userService.isPasswordCorrect(user, currentPassword)) { if (!userService.isPasswordCorrect(user, currentPassword)) {
return new RedirectView("/account?messageType=incorrectPassword"); return new RedirectView("/account?messageType=incorrectPassword");
} }
@@ -136,12 +100,45 @@ public class UserController {
return new RedirectView("/login?messageType=credsUpdated"); return new RedirectView("/login?messageType=credsUpdated");
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/change-password-on-login")
public RedirectView changePasswordOnLogin(
Principal principal,
@RequestParam(name = "currentPassword") String currentPassword,
@RequestParam(name = "newPassword") String newPassword,
HttpServletRequest request,
HttpServletResponse response,
RedirectAttributes redirectAttributes) {
if (principal == null) {
return new RedirectView("/change-creds?messageType=notAuthenticated");
}
Optional<User> userOpt = userService.findByUsername(principal.getName());
if (userOpt == null || userOpt.isEmpty()) {
return new RedirectView("/change-creds?messageType=userNotFound");
}
User user = userOpt.get();
if (!userService.isPasswordCorrect(user, currentPassword)) {
return new RedirectView("/change-creds?messageType=incorrectPassword");
}
userService.changePassword(user, newPassword);
userService.changeFirstUse(user, false);
// Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null);
return new RedirectView("/login?messageType=credsUpdated");
}
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/change-password") @PostMapping("/change-password")
public RedirectView changePassword( public RedirectView changePassword(
Principal principal, Principal principal,
@RequestParam String currentPassword, @RequestParam(name = "currentPassword") String currentPassword,
@RequestParam String newPassword, @RequestParam(name = "newPassword") String newPassword,
HttpServletRequest request, HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
RedirectAttributes redirectAttributes) { RedirectAttributes redirectAttributes) {
@@ -192,12 +189,24 @@ public class UserController {
@PreAuthorize("hasRole('ROLE_ADMIN')") @PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/admin/saveUser") @PostMapping("/admin/saveUser")
public RedirectView saveUser( public RedirectView saveUser(
@RequestParam String username, @RequestParam(name = "username") String username,
@RequestParam String password, @RequestParam(name = "password") String password,
@RequestParam String role, @RequestParam(name = "role") String role,
@RequestParam(name = "forceChange", required = false, defaultValue = "false") @RequestParam(name = "forceChange", required = false, defaultValue = "false")
boolean forceChange) { boolean forceChange) {
if (!userService.isUsernameValid(username)) {
return new RedirectView("/addUsers?messageType=invalidUsername");
}
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
if (userOpt.isPresent()) {
User user = userOpt.get();
if (user != null && user.getUsername().equalsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=usernameExists");
}
}
if (userService.usernameExists(username)) { if (userService.usernameExists(username)) {
return new RedirectView("/addUsers?messageType=usernameExists"); return new RedirectView("/addUsers?messageType=usernameExists");
} }
@@ -219,18 +228,39 @@ public class UserController {
@PreAuthorize("hasRole('ROLE_ADMIN')") @PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/admin/deleteUser/{username}") @PostMapping("/admin/deleteUser/{username}")
public String deleteUser(@PathVariable String username, Authentication authentication) { public RedirectView deleteUser(
@PathVariable(name = "username") String username, Authentication authentication) {
if (!userService.usernameExists(username)) {
return new RedirectView("/addUsers?messageType=deleteUsernameExists");
}
// Get the currently authenticated username // Get the currently authenticated username
String currentUsername = authentication.getName(); String currentUsername = authentication.getName();
// Check if the provided username matches the current session's username // Check if the provided username matches the current session's username
if (currentUsername.equals(username)) { if (currentUsername.equals(username)) {
throw new IllegalArgumentException("Cannot delete currently logined in user."); return new RedirectView("/addUsers?messageType=deleteCurrentUser");
} }
invalidateUserSessions(username);
userService.deleteUser(username); userService.deleteUser(username);
return "redirect:/addUsers"; return new RedirectView("/addUsers");
}
@Autowired private SessionRegistry sessionRegistry;
private void invalidateUserSessions(String username) {
for (Object principal : sessionRegistry.getAllPrincipals()) {
if (principal instanceof UserDetails) {
UserDetails userDetails = (UserDetails) principal;
if (userDetails.getUsername().equals(username)) {
for (SessionInformation session :
sessionRegistry.getAllSessions(principal, false)) {
session.expireNow();
}
}
}
}
} }
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")

View File

@@ -37,7 +37,7 @@ public class ConvertBookToPDFController {
if (!bookAndHtmlFormatsInstalled) { if (!bookAndHtmlFormatsInstalled) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"bookAndHtmlFormatsInstalled flag is False, this functionality is not avaiable"); "bookAndHtmlFormatsInstalled flag is False, this functionality is not available");
} }
if (fileInput == null) { if (fileInput == null) {

View File

@@ -45,7 +45,7 @@ public class ConvertPDFToBookController {
if (!bookAndHtmlFormatsInstalled) { if (!bookAndHtmlFormatsInstalled) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"bookAndHtmlFormatsInstalled flag is False, this functionality is not avaiable"); "bookAndHtmlFormatsInstalled flag is False, this functionality is not available");
} }
if (fileInput == null) { if (fileInput == null) {

View File

@@ -130,7 +130,7 @@ public class AutoRenameController {
// Sanitize the header string by removing characters not allowed in a filename. // Sanitize the header string by removing characters not allowed in a filename.
if (header != null && header.length() < 255) { if (header != null && header.length() < 255) {
header = header.replaceAll("[/\\\\?%*:|\"<>]", ""); header = header.replaceAll("[/\\\\?%*:|\"<>]", "").trim();
return WebResponseUtils.pdfDocToWebResponse(document, header + ".pdf"); return WebResponseUtils.pdfDocToWebResponse(document, header + ".pdf");
} else { } else {
logger.info("File has no good title to be found"); logger.info("File has no good title to be found");

View File

@@ -58,7 +58,7 @@ public class AutoSplitPdfController {
PDDocument document = Loader.loadPDF(file.getBytes()); PDDocument document = Loader.loadPDF(file.getBytes());
PDFRenderer pdfRenderer = new PDFRenderer(document); PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true);
List<PDDocument> splitDocuments = new ArrayList<>(); List<PDDocument> splitDocuments = new ArrayList<>();
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>(); List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();

View File

@@ -59,7 +59,7 @@ public class BlankPageController {
List<Integer> pagesToKeepIndex = new ArrayList<>(); List<Integer> pagesToKeepIndex = new ArrayList<>();
int pageIndex = 0; int pageIndex = 0;
PDFRenderer pdfRenderer = new PDFRenderer(document); PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true);
for (PDPage page : pages) { for (PDPage page : pages) {
logger.info("checking page " + pageIndex); logger.info("checking page " + pageIndex);
textStripper.setStartPage(pageIndex + 1); textStripper.setStartPage(pageIndex + 1);

View File

@@ -2,9 +2,7 @@ package stirling.software.SPDF.controller.api.misc;
import java.awt.Image; import java.awt.Image;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
@@ -75,194 +73,208 @@ public class CompressController {
long inputFileSize = Files.size(tempInputFile); long inputFileSize = Files.size(tempInputFile);
// Prepare the output file path // Prepare the output file path
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
// Determine initial optimization level based on expected size reduction, only if in
// autoMode
if (autoMode) {
double sizeReductionRatio = expectedOutputSize / (double) inputFileSize;
if (sizeReductionRatio > 0.7) {
optimizeLevel = 1;
} else if (sizeReductionRatio > 0.5) {
optimizeLevel = 2;
} else if (sizeReductionRatio > 0.35) {
optimizeLevel = 3;
} else {
optimizeLevel = 3;
}
}
boolean sizeMet = false;
while (!sizeMet && optimizeLevel <= 4) {
// Prepare the Ghostscript command
List<String> command = new ArrayList<>();
command.add("gs");
command.add("-sDEVICE=pdfwrite");
command.add("-dCompatibilityLevel=1.4");
switch (optimizeLevel) {
case 1:
command.add("-dPDFSETTINGS=/prepress");
break;
case 2:
command.add("-dPDFSETTINGS=/printer");
break;
case 3:
command.add("-dPDFSETTINGS=/ebook");
break;
case 4:
command.add("-dPDFSETTINGS=/screen");
break;
default:
command.add("-dPDFSETTINGS=/default");
}
command.add("-dNOPAUSE");
command.add("-dQUIET");
command.add("-dBATCH");
command.add("-sOutputFile=" + tempOutputFile.toString());
command.add(tempInputFile.toString());
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT)
.runCommandWithOutputHandling(command);
// Check if file size is within expected size or not auto mode so instantly finish
long outputFileSize = Files.size(tempOutputFile);
if (outputFileSize <= expectedOutputSize || !autoMode) {
sizeMet = true;
} else {
// Increase optimization level for next iteration
optimizeLevel++;
if (autoMode && optimizeLevel > 3) {
System.out.println("Skipping level 4 due to bad results in auto mode");
sizeMet = true;
} else if (optimizeLevel == 5) {
Path tempOutputFile = null;
byte[] pdfBytes;
try {
tempOutputFile = Files.createTempFile("output_", ".pdf");
// Determine initial optimization level based on expected size reduction, only if in
// autoMode
if (autoMode) {
double sizeReductionRatio = expectedOutputSize / (double) inputFileSize;
if (sizeReductionRatio > 0.7) {
optimizeLevel = 1;
} else if (sizeReductionRatio > 0.5) {
optimizeLevel = 2;
} else if (sizeReductionRatio > 0.35) {
optimizeLevel = 3;
} else { } else {
System.out.println( optimizeLevel = 3;
"Increasing ghostscript optimisation level to " + optimizeLevel);
} }
} }
}
if (expectedOutputSize != null && autoMode) { boolean sizeMet = false;
long outputFileSize = Files.size(tempOutputFile); while (!sizeMet && optimizeLevel <= 4) {
if (outputFileSize > expectedOutputSize) { // Prepare the Ghostscript command
try (PDDocument doc = Loader.loadPDF(new File(tempOutputFile.toString()))) { List<String> command = new ArrayList<>();
long previousFileSize = 0; command.add("gs");
double scaleFactor = 1.0; command.add("-sDEVICE=pdfwrite");
while (true) { command.add("-dCompatibilityLevel=1.4");
for (PDPage page : doc.getPages()) {
PDResources res = page.getResources();
for (COSName name : res.getXObjectNames()) { switch (optimizeLevel) {
PDXObject xobj = res.getXObject(name); case 1:
if (xobj instanceof PDImageXObject) { command.add("-dPDFSETTINGS=/prepress");
PDImageXObject image = (PDImageXObject) xobj; break;
case 2:
command.add("-dPDFSETTINGS=/printer");
break;
case 3:
command.add("-dPDFSETTINGS=/ebook");
break;
case 4:
command.add("-dPDFSETTINGS=/screen");
break;
default:
command.add("-dPDFSETTINGS=/default");
}
// Get the image in BufferedImage format command.add("-dNOPAUSE");
BufferedImage bufferedImage = image.getImage(); command.add("-dQUIET");
command.add("-dBATCH");
command.add("-sOutputFile=" + tempOutputFile.toString());
command.add(tempInputFile.toString());
// Calculate the new dimensions ProcessExecutorResult returnCode =
int newWidth = (int) (bufferedImage.getWidth() * scaleFactor); ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT)
int newHeight = (int) (bufferedImage.getHeight() * scaleFactor); .runCommandWithOutputHandling(command);
// If the new dimensions are zero, skip this iteration // Check if file size is within expected size or not auto mode so instantly finish
if (newWidth == 0 || newHeight == 0) { long outputFileSize = Files.size(tempOutputFile);
continue; if (outputFileSize <= expectedOutputSize || !autoMode) {
sizeMet = true;
} else {
// Increase optimization level for next iteration
optimizeLevel++;
if (autoMode && optimizeLevel > 4) {
System.out.println("Skipping level 5 due to bad results in auto mode");
sizeMet = true;
} else {
System.out.println(
"Increasing ghostscript optimisation level to " + optimizeLevel);
}
}
}
if (expectedOutputSize != null && autoMode) {
long outputFileSize = Files.size(tempOutputFile);
byte[] fileBytes = Files.readAllBytes(tempOutputFile);
if (outputFileSize > expectedOutputSize) {
try (PDDocument doc = Loader.loadPDF(fileBytes)) {
long previousFileSize = 0;
double scaleFactorConst = 0.9f;
double scaleFactor = 0.9f;
while (true) {
for (PDPage page : doc.getPages()) {
PDResources res = page.getResources();
if (res != null && res.getXObjectNames() != null) {
for (COSName name : res.getXObjectNames()) {
PDXObject xobj = res.getXObject(name);
if (xobj != null && xobj instanceof PDImageXObject) {
PDImageXObject image = (PDImageXObject) xobj;
// Get the image in BufferedImage format
BufferedImage bufferedImage = image.getImage();
// Calculate the new dimensions
int newWidth =
(int)
(bufferedImage.getWidth()
* scaleFactorConst);
int newHeight =
(int)
(bufferedImage.getHeight()
* scaleFactorConst);
// If the new dimensions are zero, skip this iteration
if (newWidth == 0 || newHeight == 0) {
continue;
}
// Otherwise, proceed with the scaling
Image scaledImage =
bufferedImage.getScaledInstance(
newWidth,
newHeight,
Image.SCALE_SMOOTH);
// Convert the scaled image back to a BufferedImage
BufferedImage scaledBufferedImage =
new BufferedImage(
newWidth,
newHeight,
BufferedImage.TYPE_INT_RGB);
scaledBufferedImage
.getGraphics()
.drawImage(scaledImage, 0, 0, null);
// Compress the scaled image
ByteArrayOutputStream compressedImageStream =
new ByteArrayOutputStream();
ImageIO.write(
scaledBufferedImage,
"jpeg",
compressedImageStream);
byte[] imageBytes = compressedImageStream.toByteArray();
compressedImageStream.close();
PDImageXObject compressedImage =
PDImageXObject.createFromByteArray(
doc,
imageBytes,
image.getCOSObject().toString());
// Replace the image in the resources with the
// compressed
// version
res.put(name, compressedImage);
}
} }
// Otherwise, proceed with the scaling
Image scaledImage =
bufferedImage.getScaledInstance(
newWidth, newHeight, Image.SCALE_SMOOTH);
// Convert the scaled image back to a BufferedImage
BufferedImage scaledBufferedImage =
new BufferedImage(
newWidth,
newHeight,
BufferedImage.TYPE_INT_RGB);
scaledBufferedImage
.getGraphics()
.drawImage(scaledImage, 0, 0, null);
// Compress the scaled image
ByteArrayOutputStream compressedImageStream =
new ByteArrayOutputStream();
ImageIO.write(
scaledBufferedImage, "jpeg", compressedImageStream);
byte[] imageBytes = compressedImageStream.toByteArray();
compressedImageStream.close();
// Convert compressed image back to PDImageXObject
ByteArrayInputStream bais =
new ByteArrayInputStream(imageBytes);
PDImageXObject compressedImage =
PDImageXObject.createFromByteArray(
doc,
imageBytes,
image.getCOSObject().toString());
// Replace the image in the resources with the compressed
// version
res.put(name, compressedImage);
} }
} }
}
// save the document to tempOutputFile again // save the document to tempOutputFile again
doc.save(tempOutputFile.toString()); doc.save(tempOutputFile.toString());
long currentSize = Files.size(tempOutputFile); long currentSize = Files.size(tempOutputFile);
// Check if the overall PDF size is still larger than expectedOutputSize // Check if the overall PDF size is still larger than expectedOutputSize
if (currentSize > expectedOutputSize) { if (currentSize > expectedOutputSize) {
// Log the current file size and scaleFactor // Log the current file size and scaleFactor
System.out.println( System.out.println(
"Current file size: " "Current file size: "
+ FileUtils.byteCountToDisplaySize(currentSize)); + FileUtils.byteCountToDisplaySize(currentSize));
System.out.println("Current scale factor: " + scaleFactor); System.out.println("Current scale factor: " + scaleFactor);
// The file is still too large, reduce scaleFactor and try again // The file is still too large, reduce scaleFactor and try again
scaleFactor *= 0.9; // reduce scaleFactor by 10% scaleFactor *= 0.9f; // reduce scaleFactor by 10%
// Avoid scaleFactor being too small, causing the image to shrink to 0 // Avoid scaleFactor being too small, causing the image to shrink to
if (scaleFactor < 0.2 || previousFileSize == currentSize) { // 0
throw new RuntimeException( if (scaleFactor < 0.2f || previousFileSize == currentSize) {
"Could not reach the desired size without excessively degrading image quality, lowest size recommended is " throw new RuntimeException(
+ FileUtils.byteCountToDisplaySize(currentSize) "Could not reach the desired size without excessively degrading image quality, lowest size recommended is "
+ ", " + FileUtils.byteCountToDisplaySize(currentSize)
+ currentSize + ", "
+ " bytes"); + currentSize
+ " bytes");
}
previousFileSize = currentSize;
} else {
// The file is small enough, break the loop
break;
} }
previousFileSize = currentSize;
} else {
// The file is small enough, break the loop
break;
} }
} }
} }
} }
// Read the optimized PDF file
pdfBytes = Files.readAllBytes(tempOutputFile);
// Check if optimized file is larger than the original
if (pdfBytes.length > inputFileSize) {
// Log the occurrence
logger.warn(
"Optimized file is larger than the original. Returning the original file instead.");
// Read the original file again
pdfBytes = Files.readAllBytes(tempInputFile);
}
} finally {
// Clean up the temporary files
Files.delete(tempInputFile);
Files.delete(tempOutputFile);
} }
// Read the optimized PDF file
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
// Check if optimized file is larger than the original
if (pdfBytes.length > inputFileSize) {
// Log the occurrence
logger.warn(
"Optimized file is larger than the original. Returning the original file instead.");
// Read the original file again
pdfBytes = Files.readAllBytes(tempInputFile);
}
// Clean up the temporary files
Files.delete(tempInputFile);
Files.delete(tempOutputFile);
// Return the optimized PDF as a response // Return the optimized PDF as a response
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()) Filenames.toSimpleFileName(inputFile.getOriginalFilename())

View File

@@ -73,111 +73,150 @@ public class ExtractImageScansController {
List<String> images = new ArrayList<>(); List<String> images = new ArrayList<>();
// Check if input file is a PDF List<Path> tempImageFiles = new ArrayList<>();
if ("pdf".equalsIgnoreCase(extension)) { Path tempInputFile = null;
// Load PDF document Path tempZipFile = null;
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) { List<Path> tempDirs = new ArrayList<>();
PDFRenderer pdfRenderer = new PDFRenderer(document);
int pageCount = document.getNumberOfPages();
images = new ArrayList<>();
// Create images of all pages try {
for (int i = 0; i < pageCount; i++) { // Check if input file is a PDF
// Create temp file to save the image if ("pdf".equalsIgnoreCase(extension)) {
Path tempFile = Files.createTempFile("image_", ".png"); // Load PDF document
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) {
PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true);
int pageCount = document.getNumberOfPages();
images = new ArrayList<>();
// Render image and save as temp file // Create images of all pages
BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300); for (int i = 0; i < pageCount; i++) {
ImageIO.write(image, "png", tempFile.toFile()); // Create temp file to save the image
Path tempFile = Files.createTempFile("image_", ".png");
// Add temp file path to images list // Render image and save as temp file
images.add(tempFile.toString()); BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300);
ImageIO.write(image, "png", tempFile.toFile());
// Add temp file path to images list
images.add(tempFile.toString());
tempImageFiles.add(tempFile);
}
} }
} else {
tempInputFile = Files.createTempFile("input_", "." + extension);
Files.copy(
form.getFileInput().getInputStream(),
tempInputFile,
StandardCopyOption.REPLACE_EXISTING);
// Add input file path to images list
images.add(tempInputFile.toString());
} }
} else {
Path tempInputFile = Files.createTempFile("input_", "." + extension);
Files.copy(
form.getFileInput().getInputStream(),
tempInputFile,
StandardCopyOption.REPLACE_EXISTING);
// Add input file path to images list
images.add(tempInputFile.toString());
}
List<byte[]> processedImageBytes = new ArrayList<>(); List<byte[]> processedImageBytes = new ArrayList<>();
// Process each image // Process each image
for (int i = 0; i < images.size(); i++) { for (int i = 0; i < images.size(); i++) {
Path tempDir = Files.createTempDirectory("openCV_output"); Path tempDir = Files.createTempDirectory("openCV_output");
List<String> command = tempDirs.add(tempDir);
new ArrayList<>( List<String> command =
Arrays.asList( new ArrayList<>(
"python3", Arrays.asList(
"./scripts/split_photos.py", "python3",
images.get(i), "./scripts/split_photos.py",
tempDir.toString(), images.get(i),
"--angle_threshold", tempDir.toString(),
String.valueOf(form.getAngleThreshold()), "--angle_threshold",
"--tolerance", String.valueOf(form.getAngleThreshold()),
String.valueOf(form.getTolerance()), "--tolerance",
"--min_area", String.valueOf(form.getTolerance()),
String.valueOf(form.getMinArea()), "--min_area",
"--min_contour_area", String.valueOf(form.getMinArea()),
String.valueOf(form.getMinContourArea()), "--min_contour_area",
"--border_size", String.valueOf(form.getMinContourArea()),
String.valueOf(form.getBorderSize()))); "--border_size",
String.valueOf(form.getBorderSize())));
// Run CLI command // Run CLI command
ProcessExecutorResult returnCode = ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV) ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
.runCommandWithOutputHandling(command); .runCommandWithOutputHandling(command);
// Read the output photos in temp directory // Read the output photos in temp directory
List<Path> tempOutputFiles = Files.list(tempDir).sorted().collect(Collectors.toList()); List<Path> tempOutputFiles =
for (Path tempOutputFile : tempOutputFiles) { Files.list(tempDir).sorted().collect(Collectors.toList());
byte[] imageBytes = Files.readAllBytes(tempOutputFile); for (Path tempOutputFile : tempOutputFiles) {
processedImageBytes.add(imageBytes); byte[] imageBytes = Files.readAllBytes(tempOutputFile);
processedImageBytes.add(imageBytes);
}
// Clean up the temporary directory
FileUtils.deleteDirectory(tempDir.toFile());
} }
// Clean up the temporary directory
FileUtils.deleteDirectory(tempDir.toFile());
}
// Create zip file if multiple images // Create zip file if multiple images
if (processedImageBytes.size() > 1) { if (processedImageBytes.size() > 1) {
String outputZipFilename = fileName.replaceFirst("[.][^.]+$", "") + "_processed.zip"; String outputZipFilename =
Path tempZipFile = Files.createTempFile("output_", ".zip"); fileName.replaceFirst("[.][^.]+$", "") + "_processed.zip";
tempZipFile = Files.createTempFile("output_", ".zip");
try (ZipOutputStream zipOut = try (ZipOutputStream zipOut =
new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) { new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) {
// Add processed images to the zip // Add processed images to the zip
for (int i = 0; i < processedImageBytes.size(); i++) { for (int i = 0; i < processedImageBytes.size(); i++) {
ZipEntry entry = ZipEntry entry =
new ZipEntry( new ZipEntry(
fileName.replaceFirst("[.][^.]+$", "") fileName.replaceFirst("[.][^.]+$", "")
+ "_" + "_"
+ (i + 1) + (i + 1)
+ ".png"); + ".png");
zipOut.putNextEntry(entry); zipOut.putNextEntry(entry);
zipOut.write(processedImageBytes.get(i)); zipOut.write(processedImageBytes.get(i));
zipOut.closeEntry(); zipOut.closeEntry();
}
}
byte[] zipBytes = Files.readAllBytes(tempZipFile);
// Clean up the temporary zip file
Files.delete(tempZipFile);
return WebResponseUtils.bytesToWebResponse(
zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
} else {
// Return the processed image as a response
byte[] imageBytes = processedImageBytes.get(0);
return WebResponseUtils.bytesToWebResponse(
imageBytes,
fileName.replaceFirst("[.][^.]+$", "") + ".png",
MediaType.IMAGE_PNG);
}
} finally {
// Cleanup logic for all temporary files and directories
tempImageFiles.forEach(
path -> {
try {
Files.deleteIfExists(path);
} catch (IOException e) {
logger.error("Failed to delete temporary image file: " + path, e);
}
});
if (tempZipFile != null && Files.exists(tempZipFile)) {
try {
Files.delete(tempZipFile);
} catch (IOException e) {
logger.error("Failed to delete temporary zip file: " + tempZipFile, e);
} }
} }
byte[] zipBytes = Files.readAllBytes(tempZipFile); tempDirs.forEach(
dir -> {
// Clean up the temporary zip file try {
Files.delete(tempZipFile); FileUtils.deleteDirectory(dir.toFile());
} catch (IOException e) {
return WebResponseUtils.bytesToWebResponse( logger.error("Failed to delete temporary directory: " + dir, e);
zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM); }
} else { });
// Return the processed image as a response
byte[] imageBytes = processedImageBytes.get(0);
return WebResponseUtils.bytesToWebResponse(
imageBytes,
fileName.replaceFirst("[.][^.]+$", "") + ".png",
MediaType.IMAGE_PNG);
} }
} }
} }

View File

@@ -60,6 +60,7 @@ public class FakeScanControllerWIP {
PDDocument document = Loader.loadPDF(inputFile.getBytes()); PDDocument document = Loader.loadPDF(inputFile.getBytes());
PDFRenderer pdfRenderer = new PDFRenderer(document); PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true);
for (int page = 0; page < document.getNumberOfPages(); ++page) { for (int page = 0; page < document.getNumberOfPages(); ++page) {
BufferedImage image = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB); BufferedImage image = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
ImageIO.write(image, "png", new File("scanned-" + (page + 1) + ".png")); ImageIO.write(image, "png", new File("scanned-" + (page + 1) + ".png"));

View File

@@ -41,7 +41,7 @@ public class OCRController {
private static final Logger logger = LoggerFactory.getLogger(OCRController.class); private static final Logger logger = LoggerFactory.getLogger(OCRController.class);
public List<String> getAvailableTesseractLanguages() { public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tesseract-ocr/5/tessdata"; String tessdataDir = "/usr/share/tessdata";
File[] files = new File(tessdataDir).listFiles(); File[] files = new File(tessdataDir).listFiles();
if (files == null) { if (files == null) {
return Collections.emptyList(); return Collections.emptyList();

View File

@@ -88,7 +88,7 @@ public class StampController {
// Load the input PDF // Load the input PDF
PDDocument document = Loader.loadPDF(pdfFile.getBytes()); PDDocument document = Loader.loadPDF(pdfFile.getBytes());
List<Integer> pageNumbers = request.getPageNumbersList(document, false); List<Integer> pageNumbers = request.getPageNumbersList(document, true);
for (int pageIndex : pageNumbers) { for (int pageIndex : pageNumbers) {
int zeroBasedIndex = pageIndex - 1; int zeroBasedIndex = pageIndex - 1;

View File

@@ -36,7 +36,7 @@ public class ApiDocService {
private String getApiDocsUrl() { private String getApiDocsUrl() {
String contextPath = servletContext.getContextPath(); String contextPath = servletContext.getContextPath();
String port = SPdfApplication.getPort(); String port = SPdfApplication.getStaticPort();
return "http://localhost:" + port + contextPath + "/v1/api-docs"; return "http://localhost:" + port + contextPath + "/v1/api-docs";
} }

View File

@@ -12,7 +12,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@@ -50,9 +49,6 @@ public class PipelineController {
@PostMapping("/handleData") @PostMapping("/handleData")
public ResponseEntity<byte[]> handleData(@ModelAttribute HandleDataRequest request) public ResponseEntity<byte[]> handleData(@ModelAttribute HandleDataRequest request)
throws JsonMappingException, JsonProcessingException { throws JsonMappingException, JsonProcessingException {
if (!Boolean.TRUE.equals(applicationProperties.getSystem().getEnableAlphaFunctionality())) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
MultipartFile[] files = request.getFileInput(); MultipartFile[] files = request.getFileInput();
String jsonString = request.getJson(); String jsonString = request.getJson();

View File

@@ -64,7 +64,7 @@ public class PipelineProcessor {
private String getBaseUrl() { private String getBaseUrl() {
String contextPath = servletContext.getContextPath(); String contextPath = servletContext.getContextPath();
String port = SPdfApplication.getPort(); String port = SPdfApplication.getStaticPort();
return "http://localhost:" + port + contextPath + "/"; return "http://localhost:" + port + contextPath + "/";
} }

View File

@@ -83,6 +83,7 @@ public class RedactController {
if (convertPDFToImage) { if (convertPDFToImage) {
PDDocument imageDocument = new PDDocument(); PDDocument imageDocument = new PDDocument();
PDFRenderer pdfRenderer = new PDFRenderer(document); PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true);
for (int page = 0; page < document.getNumberOfPages(); ++page) { for (int page = 0; page < document.getNumberOfPages(); ++page) {
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB); BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
PDPage newPage = new PDPage(new PDRectangle(bim.getWidth(), bim.getHeight())); PDPage newPage = new PDPage(new PDRectangle(bim.getWidth(), bim.getHeight()));

View File

@@ -54,33 +54,32 @@ public class SanitizeController {
boolean removeLinks = request.isRemoveLinks(); boolean removeLinks = request.isRemoveLinks();
boolean removeFonts = request.isRemoveFonts(); boolean removeFonts = request.isRemoveFonts();
try (PDDocument document = Loader.loadPDF(inputFile.getBytes())) { PDDocument document = Loader.loadPDF(inputFile.getBytes());
if (removeJavaScript) { if (removeJavaScript) {
sanitizeJavaScript(document); sanitizeJavaScript(document);
}
if (removeEmbeddedFiles) {
sanitizeEmbeddedFiles(document);
}
if (removeMetadata) {
sanitizeMetadata(document);
}
if (removeLinks) {
sanitizeLinks(document);
}
if (removeFonts) {
sanitizeFonts(document);
}
return WebResponseUtils.pdfDocToWebResponse(
document,
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_sanitized.pdf");
} }
if (removeEmbeddedFiles) {
sanitizeEmbeddedFiles(document);
}
if (removeMetadata) {
sanitizeMetadata(document);
}
if (removeLinks) {
sanitizeLinks(document);
}
if (removeFonts) {
sanitizeFonts(document);
}
return WebResponseUtils.pdfDocToWebResponse(
document,
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "_sanitized.pdf");
} }
private void sanitizeJavaScript(PDDocument document) throws IOException { private void sanitizeJavaScript(PDDocument document) throws IOException {

View File

@@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.web;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -33,6 +34,8 @@ public class AccountWebController {
return "redirect:/"; return "redirect:/";
} }
model.addAttribute("currentPage", "login");
if (request.getParameter("error") != null) { if (request.getParameter("error") != null) {
model.addAttribute("error", request.getParameter("error")); model.addAttribute("error", request.getParameter("error"));
@@ -53,6 +56,7 @@ public class AccountWebController {
public String showAddUserForm(Model model, Authentication authentication) { public String showAddUserForm(Model model, Authentication authentication) {
List<User> allUsers = userRepository.findAll(); List<User> allUsers = userRepository.findAll();
Iterator<User> iterator = allUsers.iterator(); Iterator<User> iterator = allUsers.iterator();
Map<String, String> roleDetails = Role.getAllRoleDetails();
while (iterator.hasNext()) { while (iterator.hasNext()) {
User user = iterator.next(); User user = iterator.next();
@@ -60,6 +64,7 @@ public class AccountWebController {
for (Authority authority : user.getAuthorities()) { for (Authority authority : user.getAuthorities()) {
if (authority.getAuthority().equals(Role.INTERNAL_API_USER.getRoleId())) { if (authority.getAuthority().equals(Role.INTERNAL_API_USER.getRoleId())) {
iterator.remove(); iterator.remove();
roleDetails.remove(Role.INTERNAL_API_USER.getRoleId());
break; // Break out of the inner loop once the user is removed break; // Break out of the inner loop once the user is removed
} }
} }
@@ -68,6 +73,7 @@ public class AccountWebController {
model.addAttribute("users", allUsers); model.addAttribute("users", allUsers);
model.addAttribute("currentUsername", authentication.getName()); model.addAttribute("currentUsername", authentication.getName());
model.addAttribute("roleDetails", roleDetails);
return "addUsers"; return "addUsers";
} }
@@ -112,6 +118,7 @@ public class AccountWebController {
model.addAttribute("role", user.get().getRolesAsString()); model.addAttribute("role", user.get().getRolesAsString());
model.addAttribute("settings", settingsJson); model.addAttribute("settings", settingsJson);
model.addAttribute("changeCredsFlag", user.get().isFirstLogin()); model.addAttribute("changeCredsFlag", user.get().isFirstLogin());
model.addAttribute("currentPage", "account");
} }
} else { } else {
return "redirect:/"; return "redirect:/";

View File

@@ -82,7 +82,7 @@ public class OtherWebController {
} }
public List<String> getAvailableTesseractLanguages() { public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tesseract-ocr/5/tessdata"; String tessdataDir = "/usr/share/tessdata";
File[] files = new File(tessdataDir).listFiles(); File[] files = new File(tessdataDir).listFiles();
if (files == null) { if (files == null) {
return Collections.emptyList(); return Collections.emptyList();

View File

@@ -210,7 +210,6 @@ public class ApplicationProperties {
private String rootURIPath; private String rootURIPath;
private String customStaticFilePath; private String customStaticFilePath;
private Integer maxFileSize; private Integer maxFileSize;
private CustomApplications customApplications;
private Boolean enableAlphaFunctionality; private Boolean enableAlphaFunctionality;
@@ -262,14 +261,6 @@ public class ApplicationProperties {
this.maxFileSize = maxFileSize; this.maxFileSize = maxFileSize;
} }
public CustomApplications getCustomApplications() {
return customApplications != null ? customApplications : new CustomApplications();
}
public void setCustomApplications(CustomApplications customApplications) {
this.customApplications = customApplications;
}
@Override @Override
public String toString() { public String toString() {
return "System [defaultLocale=" return "System [defaultLocale="
@@ -282,31 +273,10 @@ public class ApplicationProperties {
+ customStaticFilePath + customStaticFilePath
+ ", maxFileSize=" + ", maxFileSize="
+ maxFileSize + maxFileSize
+ ", customApplications="
+ customApplications
+ ", enableAlphaFunctionality=" + ", enableAlphaFunctionality="
+ enableAlphaFunctionality + enableAlphaFunctionality
+ "]"; + "]";
} }
public static class CustomApplications {
private boolean installBookAndHtmlFormats;
public boolean isInstallBookAndHtmlFormats() {
return installBookAndHtmlFormats;
}
public void setInstallBookAndHtmlFormats(boolean installBookAndHtmlFormats) {
this.installBookAndHtmlFormats = installBookAndHtmlFormats;
}
@Override
public String toString() {
return "CustomApplications [installBookAndHtmlFormats="
+ installBookAndHtmlFormats
+ "]";
}
}
} }
public static class Ui { public static class Ui {

View File

@@ -1,34 +1,43 @@
package stirling.software.SPDF.model; package stirling.software.SPDF.model;
import java.util.LinkedHashMap;
import java.util.Map;
public enum Role { public enum Role {
// Unlimited access // Unlimited access
ADMIN("ROLE_ADMIN", Integer.MAX_VALUE, Integer.MAX_VALUE), ADMIN("ROLE_ADMIN", Integer.MAX_VALUE, Integer.MAX_VALUE, "adminUserSettings.admin"),
// Unlimited access // Unlimited access
USER("ROLE_USER", Integer.MAX_VALUE, Integer.MAX_VALUE), USER("ROLE_USER", Integer.MAX_VALUE, Integer.MAX_VALUE, "adminUserSettings.user"),
// 40 API calls Per Day, 40 web calls // 40 API calls Per Day, 40 web calls
LIMITED_API_USER("ROLE_LIMITED_API_USER", 40, 40), LIMITED_API_USER("ROLE_LIMITED_API_USER", 40, 40, "adminUserSettings.apiUser"),
// 20 API calls Per Day, 20 web calls // 20 API calls Per Day, 20 web calls
EXTRA_LIMITED_API_USER("ROLE_EXTRA_LIMITED_API_USER", 20, 20), EXTRA_LIMITED_API_USER("ROLE_EXTRA_LIMITED_API_USER", 20, 20, "adminUserSettings.extraApiUser"),
// 0 API calls per day and 20 web calls // 0 API calls per day and 20 web calls
WEB_ONLY_USER("ROLE_WEB_ONLY_USER", 0, 20), WEB_ONLY_USER("ROLE_WEB_ONLY_USER", 0, 20, "adminUserSettings.webOnlyUser"),
INTERNAL_API_USER("STIRLING-PDF-BACKEND-API-USER", Integer.MAX_VALUE, Integer.MAX_VALUE), INTERNAL_API_USER(
"STIRLING-PDF-BACKEND-API-USER",
Integer.MAX_VALUE,
Integer.MAX_VALUE,
"adminUserSettings.internalApiUser"),
DEMO_USER("ROLE_DEMO_USER", 100, 100); DEMO_USER("ROLE_DEMO_USER", 100, 100, "adminUserSettings.demoUser");
private final String roleId; private final String roleId;
private final int apiCallsPerDay; private final int apiCallsPerDay;
private final int webCallsPerDay; private final int webCallsPerDay;
private final String roleName;
Role(String roleId, int apiCallsPerDay, int webCallsPerDay) { Role(String roleId, int apiCallsPerDay, int webCallsPerDay, String roleName) {
this.roleId = roleId; this.roleId = roleId;
this.apiCallsPerDay = apiCallsPerDay; this.apiCallsPerDay = apiCallsPerDay;
this.webCallsPerDay = webCallsPerDay; this.webCallsPerDay = webCallsPerDay;
this.roleName = roleName;
} }
public String getRoleId() { public String getRoleId() {
@@ -43,6 +52,27 @@ public enum Role {
return webCallsPerDay; return webCallsPerDay;
} }
public String getRoleName() {
return roleName;
}
public static String getRoleNameByRoleId(String roleId) {
// Using the fromString method to get the Role enum based on the roleId
Role role = fromString(roleId);
// Return the roleName of the found Role enum
return role.getRoleName();
}
// Method to retrieve all role IDs and role names
public static Map<String, String> getAllRoleDetails() {
// Using LinkedHashMap to preserve order
Map<String, String> roleDetails = new LinkedHashMap<>();
for (Role role : Role.values()) {
roleDetails.put(role.getRoleId(), role.getRoleName());
}
return roleDetails;
}
public static Role fromString(String roleId) { public static Role fromString(String roleId) {
for (Role role : Role.values()) { for (Role role : Role.values()) {
if (role.getRoleId().equalsIgnoreCase(roleId)) { if (role.getRoleId().equalsIgnoreCase(roleId)) {

View File

@@ -44,6 +44,9 @@ public class User {
@Column(name = "isFirstLogin") @Column(name = "isFirstLogin")
private Boolean isFirstLogin = false; private Boolean isFirstLogin = false;
@Column(name = "roleName")
private String roleName;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user") @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user")
private Set<Authority> authorities = new HashSet<>(); private Set<Authority> authorities = new HashSet<>();
@@ -53,6 +56,10 @@ public class User {
@CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id")) @CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id"))
private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings. private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings.
public String getRoleName() {
return Role.getRoleNameByRoleId(getRolesAsString());
}
public boolean isFirstLogin() { public boolean isFirstLogin() {
return isFirstLogin != null && isFirstLogin; return isFirstLogin != null && isFirstLogin;
} }

View File

@@ -33,13 +33,13 @@ public class PDFWithPageNums extends PDFFile {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount); return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
} }
@Hidden @Hidden
public List<Integer> getPageNumbersList(PDDocument doc, boolean zeroCount) { public List<Integer> getPageNumbersList(PDDocument doc, boolean zeroCount) {
int pageCount = 0; int pageCount = 0;
pageCount = doc.getNumberOfPages(); pageCount = doc.getNumberOfPages();
return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount); return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
} }
} }

View File

@@ -15,4 +15,7 @@ public class SplitPdfBySectionsRequest extends PDFFile {
@Schema(description = "Number of vertical divisions for each PDF page", example = "2") @Schema(description = "Number of vertical divisions for each PDF page", example = "2")
private int verticalDivisions; private int verticalDivisions;
@Schema(description = "Merge the split documents into a single PDF", example = "true")
private boolean merge;
} }

View File

@@ -12,6 +12,6 @@ public class PdfToTextOrRTFRequest extends PDFFile {
@Schema( @Schema(
description = "The output Text or RTF format", description = "The output Text or RTF format",
allowableValues = {"rtf", "txt:Text"}) allowableValues = {"rtf", "txt"})
private String outputFormat; private String outputFormat;
} }

View File

@@ -3,10 +3,14 @@ package stirling.software.SPDF.repository;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
public interface UserRepository extends JpaRepository<User, String> { public interface UserRepository extends JpaRepository<User, String> {
Optional<User> findByUsernameIgnoreCase(String username);
Optional<User> findByUsername(String username); Optional<User> findByUsername(String username);
User findByApiKey(String apiKey); User findByApiKey(String apiKey);

View File

@@ -12,11 +12,12 @@ import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.fathzer.soft.javaluator.DoubleEvaluator;
import io.github.pixee.security.HostValidator; import io.github.pixee.security.HostValidator;
import io.github.pixee.security.Urls; import io.github.pixee.security.Urls;
@@ -115,91 +116,115 @@ public class GeneralUtils {
return null; return null;
} }
public static List<Integer> parsePageString(String pageOrder, int totalPages) { public static List<Integer> parsePageList(String pages, int totalPages, boolean oneBased) {
return parsePageString(pageOrder, totalPages, false); if (pages == null) {
} return List.of(1); // Default to first page if input is null
public static List<Integer> parsePageString(
String pageOrder, int totalPages, boolean isOneBased) {
if (pageOrder == null || pageOrder.isEmpty()) {
return Collections.singletonList(1);
} }
if (pageOrder.matches("\\d+")) { try {
// Convert the single number string to an integer and return it in a list return parsePageList(pages.split(","), totalPages, oneBased);
return Collections.singletonList(Integer.parseInt(pageOrder)); } catch (NumberFormatException e) {
return List.of(1); // Default to first page if input is invalid
} }
return parsePageList(pageOrder.split(","), totalPages, isOneBased);
} }
public static List<Integer> parsePageList(String[] pageOrderArr, int totalPages) { public static List<Integer> parsePageList(String[] pages, int totalPages) {
return parsePageList(pageOrderArr, totalPages, false); return parsePageList(pages, totalPages, false);
} }
public static List<Integer> parsePageList( public static List<Integer> parsePageList(String[] pages, int totalPages, boolean oneBased) {
String[] pageOrderArr, int totalPages, boolean isOneBased) { List<Integer> result = new ArrayList<>();
List<Integer> newPageOrder = new ArrayList<>(); int offset = oneBased ? 1 : 0;
for (String page : pages) {
if ("all".equalsIgnoreCase(page)) {
int adjustmentFactor = isOneBased ? 1 : 0;
// loop through the page order array
for (String element : pageOrderArr) {
if ("all".equalsIgnoreCase(element)) {
for (int i = 0; i < totalPages; i++) { for (int i = 0; i < totalPages; i++) {
newPageOrder.add(i + adjustmentFactor); result.add(i + offset);
} }
// As all pages are already added, no need to check further } else if (page.contains(",")) {
break; // Split the string into parts, could be single pages or ranges
} else if (element.matches("\\d*n\\+?-?\\d*|\\d*\\+?n")) { String[] parts = page.split(",");
// Handle page order as a function for (String part : parts) {
int coefficient = 0; result.addAll(handlePart(part, totalPages, offset));
int constant = 0;
boolean coefficientExists = false;
boolean constantExists = false;
if (element.contains("n")) {
String[] parts = element.split("n");
if (!"".equals(parts[0]) && parts[0] != null) {
coefficient = Integer.parseInt(parts[0]);
coefficientExists = true;
}
if (parts.length > 1 && !"".equals(parts[1]) && parts[1] != null) {
constant = Integer.parseInt(parts[1]);
constantExists = true;
}
} else if (element.contains("+")) {
constant = Integer.parseInt(element.replace("+", ""));
constantExists = true;
}
for (int i = 1; i <= totalPages; i++) {
int pageNum = coefficientExists ? coefficient * i : i;
pageNum += constantExists ? constant : 0;
if (pageNum <= totalPages && pageNum > 0) {
newPageOrder.add(pageNum - adjustmentFactor);
}
}
} else if (element.contains("-")) {
// split the range into start and end page
String[] range = element.split("-");
int start = Integer.parseInt(range[0]);
int end = Integer.parseInt(range[1]);
// check if the end page is greater than total pages
if (end > totalPages) {
end = totalPages;
}
// loop through the range of pages
for (int j = start; j <= end; j++) {
// print the current index
newPageOrder.add(j - adjustmentFactor);
} }
} else { } else {
// if the element is a single page result.addAll(handlePart(page, totalPages, offset));
newPageOrder.add(Integer.parseInt(element) - adjustmentFactor);
} }
} }
return new ArrayList<>(
new java.util.LinkedHashSet<>(result)); // Remove duplicates and maintain order
}
return newPageOrder; public static List<Integer> evaluateNFunc(String expression, int maxValue) {
List<Integer> results = new ArrayList<>();
DoubleEvaluator evaluator = new DoubleEvaluator();
// Validate the expression
if (!expression.matches("[0-9n+\\-*/() ]+")) {
throw new IllegalArgumentException("Invalid expression");
}
int n = 0;
while (true) {
// Replace 'n' with the current value of n, correctly handling numbers before 'n'
String sanitizedExpression = insertMultiplicationBeforeN(expression, n);
Double result = evaluator.evaluate(sanitizedExpression);
// Check if the result is null or not within bounds
if (result == null || result <= 0 || result.intValue() > maxValue) {
if (n != 0) break;
} else {
results.add(result.intValue());
}
n++;
}
return results;
}
private static String insertMultiplicationBeforeN(String expression, int nValue) {
// Insert multiplication between a number and 'n' (e.g., "4n" becomes "4*n")
String withMultiplication = expression.replaceAll("(\\d)n", "$1*n");
// Now replace 'n' with its current value
return withMultiplication.replaceAll("n", String.valueOf(nValue));
}
private static List<Integer> handlePart(String part, int totalPages, int offset) {
List<Integer> partResult = new ArrayList<>();
// First check for n-syntax because it should not be processed as a range
if (part.contains("n")) {
partResult = evaluateNFunc(part, totalPages);
// Adjust the results according to the offset
for (int i = 0; i < partResult.size(); i++) {
int adjustedValue = partResult.get(i) - 1 + offset;
partResult.set(i, adjustedValue);
}
} else if (part.contains("-")) {
// Process ranges only if it's not n-syntax
String[] rangeParts = part.split("-");
try {
int start = Integer.parseInt(rangeParts[0]);
int end = Integer.parseInt(rangeParts[1]);
for (int i = start; i <= end; i++) {
if (i >= 1 && i <= totalPages) {
partResult.add(i - 1 + offset);
}
}
} catch (NumberFormatException e) {
// Range is invalid, ignore this part
}
} else {
// This is a single page number
try {
int pageNum = Integer.parseInt(part.trim());
if (pageNum >= 1 && pageNum <= totalPages) {
partResult.add(pageNum - 1 + offset);
}
} catch (NumberFormatException ignored) {
// Ignore invalid numbers
}
}
return partResult;
} }
public static boolean createDir(String path) { public static boolean createDir(String path) {

View File

@@ -214,6 +214,7 @@ public class PdfUtils {
throws IOException, Exception { throws IOException, Exception {
try (PDDocument document = Loader.loadPDF(inputStream)) { try (PDDocument document = Loader.loadPDF(inputStream)) {
PDFRenderer pdfRenderer = new PDFRenderer(document); PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true);
int pageCount = document.getNumberOfPages(); int pageCount = document.getNumberOfPages();
// Create a ByteArrayOutputStream to save the image(s) to // Create a ByteArrayOutputStream to save the image(s) to

View File

@@ -189,7 +189,11 @@ public class ProcessExecutor {
} }
} }
} else if (exitCode != 0) { } else if (exitCode != 0) {
throw new IOException("Command process failed with exit code " + exitCode); throw new IOException(
"Command process failed with exit code "
+ exitCode
+ "\nLogs: "
+ messages);
} }
} finally { } finally {
semaphore.release(); semaphore.release();

View File

@@ -1,6 +1,6 @@
____ _____ ___ ____ _ ___ _ _ ____ ____ ____ _____ ____ _____ ___ ____ _ ___ _ _ ____ ____ ____ _____
/ ___|_ _|_ _| _ \| | |_ _| \ | |/ ___| | _ \| _ \| ___| / ___|_ _|_ _| _ \| | |_ _| \ | |/ ___| | _ \| _ \| ___|
\___ \ | | | || |_) | | | || \| | | _ _____| |_) | | | | |_ \___ \ | | | || |_) | | | || \| | | _ _____| |_) | | | | |_
___) || | | || _ <| |___ | || |\ | |_| |_____| __/| |_| | _| ___) || | | || _ <| |___ | || |\ | |_| |_____| __/| |_| | _|
|____/ |_| |___|_| \_\_____|___|_| \_|\____| |_| |____/|_| |____/ |_| |___|_| \_\_____|___|_| \_|\____| |_| |____/|_|
Powered by Spring Boot ${spring-boot.version} Powered by Spring Boot ${spring-boot.version}

View File

@@ -1,11 +0,0 @@
fileToPDF.fileTypesList=Microsoft Word: (DOC, DOCX, DOT, DOTX) <br> \
Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF) <br> \
Microsoft PowerPoint: (PPT, PPTX) <br> \
OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG) <br> \
Plain Text: (TXT, TEXT, XML) <br> \
Rich Text Format: (RTF) <br> \
Images: (BMP, GIF, JPEG, PNG, TIF, PBM, PGM, PPM, RAS, XBM, XPM, SVG, SVM, WMF) <br> \
HTML: (HTML) <br> \
Lotus Word Pro: (LWP) <br> \
StarOffice formats: (SDA, SDC, SDD, SDW, STC, STD, STI, STW, SXD, SXG, SXI, SXW) <br> \
Other formats: (DBF, FODS, VSD, VOR, VOR3, VOR4, UOP, PCT, PS, PDF)

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=اختر صورة
genericSubmit=إرسال genericSubmit=إرسال
processTimeWarning=تحذير: يمكن أن تستغرق هذه العملية ما يصل إلى دقيقة حسب حجم الملف processTimeWarning=تحذير: يمكن أن تستغرق هذه العملية ما يصل إلى دقيقة حسب حجم الملف
pageOrderPrompt=ترتيب الصفحات (أدخل قائمة بأرقام الصفحات مفصولة بفواصل): pageOrderPrompt=ترتيب الصفحات (أدخل قائمة بأرقام الصفحات مفصولة بفواصل):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=اذهب goToPage=اذهب
true=\u0635\u062D\u064A\u062D true=\u0635\u062D\u064A\u062D
false=\u062E\u0637\u0623 false=\u062E\u0637\u0623
unknown=\u063A\u064A\u0631 \u0645\u0639\u0631\u0648\u0641 unknown=\u063A\u064A\u0631 \u0645\u0639\u0631\u0648\u0641
save=\u062D\u0641\u0638 save=\u062D\u0641\u0638
saveToBrowser=Save to Browser
close=\u0625\u063A\u0644\u0627\u0642 close=\u0625\u063A\u0644\u0627\u0642
filesSelected=الملفات المحددة filesSelected=الملفات المحددة
noFavourites=لم تتم إضافة أي مفضلات noFavourites=لم تتم إضافة أي مفضلات
downloadComplete=Download Complete
bored=الانتظار بالملل؟ bored=الانتظار بالملل؟
alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629 alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629
downloadPdf=تنزيل PDF downloadPdf=تنزيل PDF
@@ -51,12 +54,15 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=Account Settings
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -141,13 +147,16 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User adminUserSettings.apiUser=Limited API User
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Web Only User adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
############# #############
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Sign in login.title=Sign in
login.header=Sign in
login.signin=Sign in login.signin=Sign in
login.rememberme=Remember me login.rememberme=Remember me
login.invalid=Invalid username or password. login.invalid=Invalid username or password.
@@ -622,6 +641,18 @@ compare.document.1=المستند 1
compare.document.2=المستند 2 compare.document.2=المستند 2
compare.submit=يقارن compare.submit=يقارن
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=تسجيل الدخول sign.title=تسجيل الدخول
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=?????? PDFToCSV.submit=??????
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Split PDF by Size or Count split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size split-by-size-or-count.type.size=By Size
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=Изберете изображение(я)
genericSubmit=Подайте genericSubmit=Подайте
processTimeWarning=Предупреждение: Този процес може да отнеме до минута в зависимост от размера на файла processTimeWarning=Предупреждение: Този процес може да отнеме до минута в зависимост от размера на файла
pageOrderPrompt=Персонализиран ред на страниците (Въведете разделен със запетаи списък с номера на страници или функции като 2n+1): pageOrderPrompt=Персонализиран ред на страниците (Въведете разделен със запетаи списък с номера на страници или функции като 2n+1):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Давай goToPage=Давай
true=Вярно true=Вярно
false=Невярно false=Невярно
unknown=Непознат unknown=Непознат
save=Съхранете save=Съхранете
saveToBrowser=Save to Browser
close=Затворете close=Затворете
filesSelected=избрани файлове filesSelected=избрани файлове
noFavourites=Няма добавени любими noFavourites=Няма добавени любими
downloadComplete=Download Complete
bored=Отекчени сте да чакате? bored=Отекчени сте да чакате?
alphabet=Азбука alphabet=Азбука
downloadPdf=Изтеглете PDF downloadPdf=Изтеглете PDF
@@ -51,12 +54,15 @@ notAuthenticatedMessage=Потребителят не е автентикира
userNotFoundMessage=Потребителят не е намерен userNotFoundMessage=Потребителят не е намерен
incorrectPasswordMessage=Текущата парола е неправилна. incorrectPasswordMessage=Текущата парола е неправилна.
usernameExistsMessage=Новият потребител вече съществува. usernameExistsMessage=Новият потребител вече съществува.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=Настройки на акаунта
changeCreds.title=Промяна на идентификационните данни changeCreds.title=Промяна на идентификационните данни
changeCreds.header=Актуализирайте данните за акаунта си changeCreds.header=Актуализирайте данните за акаунта си
changeCreds.changeUserAndPassword=Използвате идентификационни данни за вход по подразбиране. Моля, въведете нова парола (и потребителско име, ако искате) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Ново потребителско име changeCreds.newUsername=Ново потребителско име
changeCreds.oldPassword=Текуща парола changeCreds.oldPassword=Текуща парола
changeCreds.newPassword=Нова парола changeCreds.newPassword=Нова парола
@@ -141,12 +147,15 @@ adminUserSettings.header=Настройки за администраторск
adminUserSettings.admin=Администратор adminUserSettings.admin=Администратор
adminUserSettings.user=Потребител adminUserSettings.user=Потребител
adminUserSettings.addUser=Добавяне на нов потребител adminUserSettings.addUser=Добавяне на нов потребител
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Роли adminUserSettings.roles=Роли
adminUserSettings.role=Роля adminUserSettings.role=Роля
adminUserSettings.actions=Действия adminUserSettings.actions=Действия
adminUserSettings.apiUser=Ограничен API потребител adminUserSettings.apiUser=Ограничен API потребител
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Само за уеб-потребител adminUserSettings.webOnlyUser=Само за уеб-потребител
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане
adminUserSettings.submit=Съхранете потребителя adminUserSettings.submit=Съхранете потребителя
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Вход login.title=Вход
login.header=Вход
login.signin=Впишете се login.signin=Впишете се
login.rememberme=Запомни ме login.rememberme=Запомни ме
login.invalid=Невалидно потребителско име или парола. login.invalid=Невалидно потребителско име или парола.
@@ -622,6 +641,18 @@ compare.document.1=Документ 1
compare.document.2=Документ 2 compare.document.2=Документ 2
compare.submit=Сравнявай compare.submit=Сравнявай
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Подпишете sign.title=Подпишете
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=???????? PDFToCSV.submit=????????
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Split PDF by Size or Count split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size split-by-size-or-count.type.size=By Size
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=Selecciona Imatge(s)
genericSubmit=Envia genericSubmit=Envia
processTimeWarning=Alerta: Aquest procés pot tardar 1 minut depenent de la mida de l'arxiu processTimeWarning=Alerta: Aquest procés pot tardar 1 minut depenent de la mida de l'arxiu
pageOrderPrompt=Ordre de Pàgines (Llista separada per comes) : pageOrderPrompt=Ordre de Pàgines (Llista separada per comes) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Anar goToPage=Anar
true=Verdader true=Verdader
false=Fals false=Fals
unknown=Desconegut unknown=Desconegut
save=Desa save=Desa
saveToBrowser=Save to Browser
close=Tanca close=Tanca
filesSelected=fitxers seleccionats filesSelected=fitxers seleccionats
noFavourites=No s'ha afegit cap favorit noFavourites=No s'ha afegit cap favorit
downloadComplete=Download Complete
bored=Avorrit esperant? bored=Avorrit esperant?
alphabet=Alfabet alphabet=Alfabet
downloadPdf=Descarregueu PDF downloadPdf=Descarregueu PDF
@@ -51,12 +54,15 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=Account Settings
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -141,13 +147,16 @@ adminUserSettings.header=Usuari Admin Opcions Control
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Usuari adminUserSettings.user=Usuari
adminUserSettings.addUser=Afegir Usuari adminUserSettings.addUser=Afegir Usuari
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Rols adminUserSettings.roles=Rols
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Accions adminUserSettings.actions=Accions
adminUserSettings.apiUser=Usuari amb API limitada adminUserSettings.apiUser=Usuari amb API limitada
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Usuari només WEB adminUserSettings.webOnlyUser=Usuari només WEB
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Desar Usuari adminUserSettings.submit=Desar Usuari
############# #############
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Accedir login.title=Accedir
login.header=Accedir
login.signin=Accedir login.signin=Accedir
login.rememberme=Recordar login.rememberme=Recordar
login.invalid=Nom usuari / password no vàlid login.invalid=Nom usuari / password no vàlid
@@ -622,6 +641,18 @@ compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Comparar compare.submit=Comparar
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Sign sign.title=Sign
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=Extracte PDFToCSV.submit=Extracte
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Split PDF by Size or Count split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size split-by-size-or-count.type.size=By Size
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -8,17 +8,20 @@ pdfPrompt=PDF auswählen
multiPdfPrompt=PDFs auswählen(2+) multiPdfPrompt=PDFs auswählen(2+)
multiPdfDropPrompt=Wählen Sie alle gewünschten PDFs aus (oder ziehen Sie sie per Drag & Drop hierhin) multiPdfDropPrompt=Wählen Sie alle gewünschten PDFs aus (oder ziehen Sie sie per Drag & Drop hierhin)
imgPrompt=Wählen Sie ein Bild imgPrompt=Wählen Sie ein Bild
genericSubmit=Einreichen genericSubmit=Absenden
processTimeWarning=Achtung: Abhängig von der Dateigröße kann dieser Prozess bis zu einer Minute dauern processTimeWarning=Achtung: Abhängig von der Dateigröße kann dieser Prozess bis zu einer Minute dauern
pageOrderPrompt=Seitenreihenfolge (Geben Sie eine durch Komma getrennte Liste von Seitenzahlen ein): pageOrderPrompt=Seitenreihenfolge (Geben Sie eine durch Komma getrennte Liste von Seitenzahlen ein):
pageSelectionPrompt=Benutzerdefinierte Seitenauswahl (Geben Sie eine durch Kommas getrennte Liste von Seitenzahlen 1,5,6 oder Funktionen wie 2n+1 ein):
goToPage=Los goToPage=Los
true=Wahr true=Wahr
false=Falsch false=Falsch
unknown=Unbekannt unknown=Unbekannt
save=Speichern save=Speichern
saveToBrowser=Save to Browser
close=Schließen close=Schließen
filesSelected=Dateien ausgewählt filesSelected=Dateien ausgewählt
noFavourites=Keine Favoriten hinzugefügt noFavourites=Keine Favoriten hinzugefügt
downloadComplete=Download abgeschlossen
bored=Langeweile beim Warten? bored=Langeweile beim Warten?
alphabet=Alphabet alphabet=Alphabet
downloadPdf=PDF herunterladen downloadPdf=PDF herunterladen
@@ -51,6 +54,9 @@ notAuthenticatedMessage=Benutzer nicht authentifiziert.
userNotFoundMessage=Benutzer nicht gefunden. userNotFoundMessage=Benutzer nicht gefunden.
incorrectPasswordMessage=Das Passwort ist falsch. incorrectPasswordMessage=Das Passwort ist falsch.
usernameExistsMessage=Neuer Benutzername existiert bereits. usernameExistsMessage=Neuer Benutzername existiert bereits.
invalidUsernameMessage=Ungültiger Benutzername. Der Benutzername darf nur Buchstaben und Zahlen enthalten.
deleteCurrentUserMessage=Der aktuell angemeldete Benutzer kann nicht gelöscht werden.
deleteUsernameExistsMessage=Der Benutzername existiert nicht und kann nicht gelöscht werden.
############### ###############
@@ -67,12 +73,12 @@ pipeline.submitButton=Speichern
###################### ######################
pipelineOptions.header=Pipeline-Konfiguration pipelineOptions.header=Pipeline-Konfiguration
pipelineOptions.pipelineNameLabel=Pipeline-Name pipelineOptions.pipelineNameLabel=Pipeline-Name
pipelineOptions.saveSettings=Save Operation Settings pipelineOptions.saveSettings=Operations-Einstellungen speichern
pipelineOptions.pipelineNamePrompt=Geben Sie hier den Namen der Pipeline ein pipelineOptions.pipelineNamePrompt=Geben Sie hier den Namen der Pipeline ein
pipelineOptions.selectOperation=Vorgang auswählen pipelineOptions.selectOperation=Vorgang auswählen
pipelineOptions.addOperationButton=Vorgang hinzufügen pipelineOptions.addOperationButton=Vorgang hinzufügen
pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Downloaden pipelineOptions.saveButton=Herunterladen
pipelineOptions.validateButton=Validieren pipelineOptions.validateButton=Validieren
@@ -84,7 +90,7 @@ pipelineOptions.validateButton=Validieren
navbar.convert=Konvertieren navbar.convert=Konvertieren
navbar.security=Sicherheit navbar.security=Sicherheit
navbar.other=Anderes navbar.other=Anderes
navbar.darkmode=Dark Mode navbar.darkmode=Dunkler Modus
navbar.pageOps=Seitenoperationen navbar.pageOps=Seitenoperationen
navbar.settings=Einstellungen navbar.settings=Einstellungen
@@ -106,7 +112,7 @@ settings.accountSettings=Kontoeinstellungen
changeCreds.title=Anmeldeinformationen ändern changeCreds.title=Anmeldeinformationen ändern
changeCreds.header=Aktualisieren Sie Ihre Kontodaten changeCreds.header=Aktualisieren Sie Ihre Kontodaten
changeCreds.changeUserAndPassword=Sie verwenden Standard-Anmeldeinformationen. Bitte geben Sie ein neues Passwort (und ggf. einen Benutzernamen) ein. changeCreds.changePassword=Sie verwenden die Standard-Zugangsdaten. Bitte geben Sie ein neues Passwort ein.
changeCreds.newUsername=Neuer Benutzername changeCreds.newUsername=Neuer Benutzername
changeCreds.oldPassword=Aktuelles Passwort changeCreds.oldPassword=Aktuelles Passwort
changeCreds.newPassword=Neues Passwort changeCreds.newPassword=Neues Passwort
@@ -127,7 +133,7 @@ account.newPassword=Neues Passwort
account.changePassword=Passwort ändern account.changePassword=Passwort ändern
account.confirmNewPassword=Neues Passwort bestätigen account.confirmNewPassword=Neues Passwort bestätigen
account.signOut=Abmelden account.signOut=Abmelden
account.yourApiKey=Dein API Schlüssel account.yourApiKey=Dein API-Schlüssel
account.syncTitle=Browsereinstellungen mit Konto synchronisieren account.syncTitle=Browsereinstellungen mit Konto synchronisieren
account.settingsCompare=Einstellungen vergleichen: account.settingsCompare=Einstellungen vergleichen:
account.property=Eigenschaft account.property=Eigenschaft
@@ -141,12 +147,15 @@ adminUserSettings.header=Administrator-Benutzerkontrolle
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Benutzer adminUserSettings.user=Benutzer
adminUserSettings.addUser=Neuen Benutzer hinzufügen adminUserSettings.addUser=Neuen Benutzer hinzufügen
adminUserSettings.usernameInfo=Der Benutzername darf nur Buchstaben und Zahlen enthalten, keine Leerzeichen oder Sonderzeichen.
adminUserSettings.roles=Rollen adminUserSettings.roles=Rollen
adminUserSettings.role=Rolle adminUserSettings.role=Rolle
adminUserSettings.actions=Aktion adminUserSettings.actions=Aktion
adminUserSettings.apiUser=Eingeschränkter API-Benutzer adminUserSettings.apiUser=Eingeschränkter API-Benutzer
adminUserSettings.extraApiUser=Zusätzlicher eingeschränkter API-Benutzer
adminUserSettings.webOnlyUser=Nur Web-Benutzer adminUserSettings.webOnlyUser=Nur Web-Benutzer
adminUserSettings.demoUser=Demo-Benutzer (Keine benutzerdefinierten Einstellungen) adminUserSettings.demoUser=Demo-Benutzer (Keine benutzerdefinierten Einstellungen)
adminUserSettings.internalApiUser=Interner API-Benutzer
adminUserSettings.forceChange=Benutzer dazu zwingen, Benutzernamen/Passwort bei der Anmeldung zu ändern adminUserSettings.forceChange=Benutzer dazu zwingen, Benutzernamen/Passwort bei der Anmeldung zu ändern
adminUserSettings.submit=Benutzer speichern adminUserSettings.submit=Benutzer speichern
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Fügen Sie an festgelegten Stellen Text oder Bildstemp
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,11 +416,12 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Anmelden login.title=Anmelden
login.header=Anmelden
login.signin=Anmelden login.signin=Anmelden
login.rememberme=Angemeldet bleiben login.rememberme=Angemeldet bleiben
login.invalid=Ungültiger Benutzername oder Passwort. login.invalid=Benutzername oder Passwort ungültig.
login.locked=Ihr Konto wurde gesperrt. login.locked=Ihr Konto wurde gesperrt.
login.signinTitle=Bitte melden Sie sich an login.signinTitle=Bitte melden Sie sich an.
#auto-redact #auto-redact
@@ -622,6 +641,18 @@ compare.document.1=Dokument 1
compare.document.2=Dokument 2 compare.document.2=Dokument 2
compare.submit=Vergleichen compare.submit=Vergleichen
#BookToPDF
BookToPDF.title=Bücher und Comics zu PDF
BookToPDF.header=Buch zu PDF
BookToPDF.credit=Verwendet Calibre
BookToPDF.submit=Konvertieren
#PDFToBook
PDFToBook.title=PDF zu Buch
PDFToBook.header=PDF zu Buch
PDFToBook.selectText.1=Format
PDFToBook.credit=Verwendet Calibre
PDFToBook.submit=Konvertieren
#sign #sign
sign.title=Signieren sign.title=Signieren
@@ -746,7 +777,7 @@ pageRemover.submit=Seiten löschen
rotate.title=PDF drehen rotate.title=PDF drehen
rotate.header=PDF drehen rotate.header=PDF drehen
rotate.selectAngle=Wählen Sie den Winkel (in Vielfachen von 90 Grad): rotate.selectAngle=Wählen Sie den Winkel (in Vielfachen von 90 Grad):
rotate.submit=Drehen rotate.submit=Herunterladen
#merge #merge
@@ -905,15 +936,15 @@ PDFToText.submit=Konvertieren
#PDFToHTML #PDFToHTML
PDFToHTML.title=PDF in HTML PDFToHTML.title=PDF zu HTML
PDFToHTML.header=PDF in HTML PDFToHTML.header=PDF zu HTML
PDFToHTML.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung. PDFToHTML.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung.
PDFToHTML.submit=Konvertieren PDFToHTML.submit=Konvertieren
#PDFToXML #PDFToXML
PDFToXML.title=PDF in XML PDFToXML.title=PDF zu XML
PDFToXML.header=PDF in XML PDFToXML.header=PDF zu XML
PDFToXML.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung. PDFToXML.credit=Dieser Dienst verwendet LibreOffice für die Dateikonvertierung.
PDFToXML.submit=Konvertieren PDFToXML.submit=Konvertieren
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Seite mit der zu extrahierenden Tabelle wählen
PDFToCSV.submit=Extrahieren PDFToCSV.submit=Extrahieren
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=PDF nach Größe oder Anzahl teilen
split-by-size-or-count.header=PDF nach Größe oder Anzahl teilen split-by-size-or-count.header=PDF nach Größe oder Anzahl teilen
split-by-size-or-count.type.label=Teil-Modus wählen split-by-size-or-count.type.label=Teil-Modus wählen
split-by-size-or-count.type.size=Nach Größe split-by-size-or-count.type.size=Nach Größe
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vertikale Teiler
split-by-sections.horizontal.placeholder=Anzahl horizontaler Teiler eingeben split-by-sections.horizontal.placeholder=Anzahl horizontaler Teiler eingeben
split-by-sections.vertical.placeholder=Anzahl vertikaler Teiler eingeben split-by-sections.vertical.placeholder=Anzahl vertikaler Teiler eingeben
split-by-sections.submit=PDF teilen split-by-sections.submit=PDF teilen
split-by-sections.merge=In eine PDF zusammenfügen
#licenses #licenses
licenses.nav=Lizenzen licenses.nav=Lizenzen

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE \u0395\u03B9\u03BA\u03CC\u0
genericSubmit=\u03A5\u03C0\u03BF\u03B2\u03BF\u03BB\u03AE genericSubmit=\u03A5\u03C0\u03BF\u03B2\u03BF\u03BB\u03AE
processTimeWarning=\u03A0\u03C1\u03BF\u03C3\u03BF\u03C7\u03AE: \u0391\u03C5\u03C4\u03AE \u03B7 \u03B4\u03B9\u03B1\u03B4\u03B9\u03BA\u03B1\u03C3\u03AF\u03B1 \u03BC\u03C0\u03BF\u03C1\u03B5\u03AF \u03BD\u03B1 \u03B4\u03B9\u03B1\u03C1\u03BA\u03AD\u03C3\u03B5\u03B9 \u03AD\u03C9\u03C2 \u03BA\u03B1\u03B9 \u03AD\u03BD\u03B1 \u03BB\u03B5\u03C0\u03C4\u03CC \u03B1\u03BD\u03AC\u03BB\u03BF\u03B3\u03B1 \u03BC\u03B5 \u03C4\u03BF \u03BC\u03AD\u03B3\u03B5\u03B8\u03BF\u03C2 \u03C4\u03BF\u03C5 \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5 processTimeWarning=\u03A0\u03C1\u03BF\u03C3\u03BF\u03C7\u03AE: \u0391\u03C5\u03C4\u03AE \u03B7 \u03B4\u03B9\u03B1\u03B4\u03B9\u03BA\u03B1\u03C3\u03AF\u03B1 \u03BC\u03C0\u03BF\u03C1\u03B5\u03AF \u03BD\u03B1 \u03B4\u03B9\u03B1\u03C1\u03BA\u03AD\u03C3\u03B5\u03B9 \u03AD\u03C9\u03C2 \u03BA\u03B1\u03B9 \u03AD\u03BD\u03B1 \u03BB\u03B5\u03C0\u03C4\u03CC \u03B1\u03BD\u03AC\u03BB\u03BF\u03B3\u03B1 \u03BC\u03B5 \u03C4\u03BF \u03BC\u03AD\u03B3\u03B5\u03B8\u03BF\u03C2 \u03C4\u03BF\u03C5 \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5
pageOrderPrompt=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03C3\u03BC\u03AD\u03BD\u03B7 \u03A3\u03B5\u03B9\u03C1\u03AC \u03A3\u03B5\u03BB\u03AF\u03B4\u03B1\u03C2 (\u03A0\u03C1\u03BF\u03C3\u03B8\u03AD\u03C3\u03C4\u03B5 \u03BC\u03AF\u03B1 \u03BB\u03AF\u03C3\u03C4\u03B5 \u03B1\u03C0\u03BF \u03B1\u03C1\u03B9\u03B8\u03BC\u03BF\u03CD\u03C2 \u03C3\u03B5\u03BB\u03B9\u03B4\u03CE\u03BD, \u03C7\u03C9\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03B5\u03C2 \u03BC\u03B5 \u03BA\u03CC\u03BC\u03BC\u03B1 \u03AE \u03C3\u03C5\u03BD\u03B1\u03C1\u03C4\u03AE\u03C3\u03B5\u03B9\u03C2 \u03CC\u03C0\u03C9\u03C2 2n+1) : pageOrderPrompt=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03C3\u03BC\u03AD\u03BD\u03B7 \u03A3\u03B5\u03B9\u03C1\u03AC \u03A3\u03B5\u03BB\u03AF\u03B4\u03B1\u03C2 (\u03A0\u03C1\u03BF\u03C3\u03B8\u03AD\u03C3\u03C4\u03B5 \u03BC\u03AF\u03B1 \u03BB\u03AF\u03C3\u03C4\u03B5 \u03B1\u03C0\u03BF \u03B1\u03C1\u03B9\u03B8\u03BC\u03BF\u03CD\u03C2 \u03C3\u03B5\u03BB\u03B9\u03B4\u03CE\u03BD, \u03C7\u03C9\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03B5\u03C2 \u03BC\u03B5 \u03BA\u03CC\u03BC\u03BC\u03B1 \u03AE \u03C3\u03C5\u03BD\u03B1\u03C1\u03C4\u03AE\u03C3\u03B5\u03B9\u03C2 \u03CC\u03C0\u03C9\u03C2 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Go goToPage=Go
true=\u0391\u03BB\u03B7\u03B8\u03AD\u03C2 true=\u0391\u03BB\u03B7\u03B8\u03AD\u03C2
false=\u039B\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF false=\u039B\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF
unknown=\u0386\u03B3\u03BD\u03C9\u03C3\u03C4\u03BF unknown=\u0386\u03B3\u03BD\u03C9\u03C3\u03C4\u03BF
save=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7 save=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7
saveToBrowser=Save to Browser
close=\u039A\u03BB\u03B5\u03AF\u03C3\u03B9\u03BC\u03BF close=\u039A\u03BB\u03B5\u03AF\u03C3\u03B9\u03BC\u03BF
filesSelected=\u03B1\u03C1\u03C7\u03B5\u03AF\u03B1 \u03C0\u03BF\u03C5 \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03B8\u03B7\u03BA\u03B1\u03BD filesSelected=\u03B1\u03C1\u03C7\u03B5\u03AF\u03B1 \u03C0\u03BF\u03C5 \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03B8\u03B7\u03BA\u03B1\u03BD
noFavourites=\u039A\u03B1\u03BD\u03AD\u03BD\u03B1 \u03B1\u03B3\u03B1\u03C0\u03AE\u03BC\u03B5\u03BD\u03BF \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03C0\u03C1\u03BF\u03C3\u03C4\u03B5\u03B8\u03B5\u03AF noFavourites=\u039A\u03B1\u03BD\u03AD\u03BD\u03B1 \u03B1\u03B3\u03B1\u03C0\u03AE\u03BC\u03B5\u03BD\u03BF \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03C0\u03C1\u03BF\u03C3\u03C4\u03B5\u03B8\u03B5\u03AF
downloadComplete=Download Complete
bored=\u0392\u03B1\u03C1\u03B9\u03AD\u03C3\u03C4\u03B5 \u03BD\u03B1 \u03C0\u03B5\u03C1\u03B9\u03BC\u03AD\u03BD\u03B5\u03C4\u03B5; bored=\u0392\u03B1\u03C1\u03B9\u03AD\u03C3\u03C4\u03B5 \u03BD\u03B1 \u03C0\u03B5\u03C1\u03B9\u03BC\u03AD\u03BD\u03B5\u03C4\u03B5;
alphabet=\u0391\u03BB\u03C6\u03AC\u03B2\u03B7\u03C4\u03BF alphabet=\u0391\u03BB\u03C6\u03AC\u03B2\u03B7\u03C4\u03BF
downloadPdf=\u039A\u03B1\u03C4\u03AD\u03B2\u03B1\u03C3\u03BC\u03B1 \u03C4\u03BF\u03C5 PDF downloadPdf=\u039A\u03B1\u03C4\u03AD\u03B2\u03B1\u03C3\u03BC\u03B1 \u03C4\u03BF\u03C5 PDF
@@ -51,12 +54,15 @@ notAuthenticatedMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4
userNotFoundMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03B2\u03C1\u03AD\u03B8\u03B7\u03BA\u03B5. userNotFoundMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03B2\u03C1\u03AD\u03B8\u03B7\u03BA\u03B5.
incorrectPasswordMessage=\u039F \u03C4\u03C1\u03AD\u03C7\u03C9\u03BD \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03BB\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF\u03C2. incorrectPasswordMessage=\u039F \u03C4\u03C1\u03AD\u03C7\u03C9\u03BD \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03BB\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF\u03C2.
usernameExistsMessage=\u03A4\u03BF \u03BD\u03AD\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03C5\u03C0\u03AC\u03C1\u03C7\u03B5\u03B9 \u03AE\u03B4\u03B7. usernameExistsMessage=\u03A4\u03BF \u03BD\u03AD\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03C5\u03C0\u03AC\u03C1\u03C7\u03B5\u03B9 \u03AE\u03B4\u03B7.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=\u03A1\u03C5\u03B8\u03BC\u03AF\u03C3\u03B5\u03B9\u03C2
changeCreds.title=\u0391\u03BB\u03BB\u03B1\u03B3\u03AE \u0394\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03B7\u03C1\u03AF\u03C9\u03BD changeCreds.title=\u0391\u03BB\u03BB\u03B1\u03B3\u03AE \u0394\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03B7\u03C1\u03AF\u03C9\u03BD
changeCreds.header=\u0395\u03BD\u03B7\u03BC\u03AD\u03C1\u03C9\u03C3\u03B7 \u03C4\u03C9\u03BD \u03BB\u03B5\u03C0\u03C4\u03BF\u03BC\u03B5\u03C1\u03B5\u03B9\u03CE\u03BD \u03C4\u03BF\u03C5 \u039B\u03BF\u03B3\u03B1\u03C1\u03B9\u03B1\u03C3\u03BC\u03BF\u03CD \u03C3\u03B1\u03C2 changeCreds.header=\u0395\u03BD\u03B7\u03BC\u03AD\u03C1\u03C9\u03C3\u03B7 \u03C4\u03C9\u03BD \u03BB\u03B5\u03C0\u03C4\u03BF\u03BC\u03B5\u03C1\u03B5\u03B9\u03CE\u03BD \u03C4\u03BF\u03C5 \u039B\u03BF\u03B3\u03B1\u03C1\u03B9\u03B1\u03C3\u03BC\u03BF\u03CD \u03C3\u03B1\u03C2
changeCreds.changeUserAndPassword=\u03A7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03B5\u03AF\u03C4\u03B5 \u03C4\u03B1 \u03C0\u03C1\u03BF\u03B5\u03C0\u03B9\u03BB\u03B5\u03B3\u03BC\u03AD\u03BD\u03B1 \u03B4\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03AE\u03C1\u03B9\u03B1 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7\u03C2. \u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B5\u03B9\u03C3\u03AC\u03B3\u03B5\u03C4\u03B5 \u03BD\u03AD\u03BF \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 (\u03BA\u03B1\u03B9 \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03B1\u03BD \u03C4\u03BF \u03B5\u03C0\u03B9\u03B8\u03C5\u03BC\u03B5\u03AF\u03C4\u03B5) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=\u039D\u03AD\u03BF \u038C\u03BD\u03BF\u03BC\u03B1 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7 changeCreds.newUsername=\u039D\u03AD\u03BF \u038C\u03BD\u03BF\u03BC\u03B1 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7
changeCreds.oldPassword=\u03A4\u03C1\u03AD\u03C7\u03C9\u03BD \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 changeCreds.oldPassword=\u03A4\u03C1\u03AD\u03C7\u03C9\u03BD \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
changeCreds.newPassword=\u039D\u03AD\u03BF\u03C2 \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 changeCreds.newPassword=\u039D\u03AD\u03BF\u03C2 \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
@@ -141,12 +147,15 @@ adminUserSettings.header=\u03A1\u03C5\u03B8\u03BC\u03AF\u03C3\u03B5\u03B9\u03C2
adminUserSettings.admin=\u0394\u03B9\u03B1\u03C7\u03B5\u03B9\u03C1\u03B9\u03C3\u03C4\u03AE\u03C2 adminUserSettings.admin=\u0394\u03B9\u03B1\u03C7\u03B5\u03B9\u03C1\u03B9\u03C3\u03C4\u03AE\u03C2
adminUserSettings.user=\u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 adminUserSettings.user=\u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2
adminUserSettings.addUser=\u03A0\u03C1\u03BF\u03C3\u03B8\u03AE\u03BA\u03B7 \u03BD\u03AD\u03BF\u03C5 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7 adminUserSettings.addUser=\u03A0\u03C1\u03BF\u03C3\u03B8\u03AE\u03BA\u03B7 \u03BD\u03AD\u03BF\u03C5 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=\u03A1\u03CC\u03BB\u03BF\u03B9 adminUserSettings.roles=\u03A1\u03CC\u03BB\u03BF\u03B9
adminUserSettings.role=\u03A1\u03CC\u03BB\u03BF\u03C2 adminUserSettings.role=\u03A1\u03CC\u03BB\u03BF\u03C2
adminUserSettings.actions=\u0395\u03BD\u03AD\u03C1\u03B3\u03B5\u03B9\u03B5\u03C2 adminUserSettings.actions=\u0395\u03BD\u03AD\u03C1\u03B3\u03B5\u03B9\u03B5\u03C2
adminUserSettings.apiUser=\u03A0\u03B5\u03C1\u03B9\u03BF\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03BF\u03C2 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B3\u03B9\u03B1 \u03B4\u03B9\u03B5\u03C0\u03B1\u03C6\u03AE \u03C0\u03C1\u03BF\u03B3\u03C1\u03B1\u03BC\u03BC\u03B1\u03C4\u03B9\u03C3\u03BC\u03BF\u03CD \u03B5\u03C6\u03B1\u03C1\u03BC\u03BF\u03B3\u03CE\u03BD (API User) adminUserSettings.apiUser=\u03A0\u03B5\u03C1\u03B9\u03BF\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03BF\u03C2 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B3\u03B9\u03B1 \u03B4\u03B9\u03B5\u03C0\u03B1\u03C6\u03AE \u03C0\u03C1\u03BF\u03B3\u03C1\u03B1\u03BC\u03BC\u03B1\u03C4\u03B9\u03C3\u03BC\u03BF\u03CD \u03B5\u03C6\u03B1\u03C1\u03BC\u03BF\u03B3\u03CE\u03BD (API User)
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=\u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03BC\u03CC\u03BD\u03BF \u0399\u03C3\u03C4\u03BF\u03CD adminUserSettings.webOnlyUser=\u03A7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03BC\u03CC\u03BD\u03BF \u0399\u03C3\u03C4\u03BF\u03CD
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=\u0391\u03BD\u03B1\u03B3\u03BA\u03AC\u03C3\u03C4\u03B5 \u03C4\u03BF\u03BD \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03BD\u03B1 \u03B1\u03BB\u03BB\u03AC\u03BE\u03B5\u03B9 \u03C4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7/\u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03BA\u03B1\u03C4\u03AC \u03C4\u03B7 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7 adminUserSettings.forceChange=\u0391\u03BD\u03B1\u03B3\u03BA\u03AC\u03C3\u03C4\u03B5 \u03C4\u03BF\u03BD \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03BD\u03B1 \u03B1\u03BB\u03BB\u03AC\u03BE\u03B5\u03B9 \u03C4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7/\u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03BA\u03B1\u03C4\u03AC \u03C4\u03B7 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7
adminUserSettings.submit=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7 adminUserSettings.submit=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7 \u03A7\u03C1\u03AE\u03C3\u03C4\u03B7
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=\u0395\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2 login.title=\u0395\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2
login.header=\u0395\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2
login.signin=\u0395\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2 login.signin=\u0395\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2
login.rememberme=\u039D\u03B1 \u039C\u03B5 \u0398\u03C5\u03BC\u03AC\u03C3\u03B1\u03B9 login.rememberme=\u039D\u03B1 \u039C\u03B5 \u0398\u03C5\u03BC\u03AC\u03C3\u03B1\u03B9
login.invalid=\u039B\u03AC\u03B8\u03BF\u03C2 \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03AE \u03BA\u03C9\u03B4\u03B9\u03BA\u03BF\u03CD \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2. login.invalid=\u039B\u03AC\u03B8\u03BF\u03C2 \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03AE \u03BA\u03C9\u03B4\u03B9\u03BA\u03BF\u03CD \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2.
@@ -622,6 +641,18 @@ compare.document.1=\u0388\u03B3\u03B3\u03C1\u03B1\u03C6\u03BF 1
compare.document.2=\u0388\u03B3\u03B3\u03C1\u03B1\u03C6\u03BF 2 compare.document.2=\u0388\u03B3\u03B3\u03C1\u03B1\u03C6\u03BF 2
compare.submit=\u03A3\u03CD\u03B3\u03BA\u03C1\u03B9\u03C3\u03B7 compare.submit=\u03A3\u03CD\u03B3\u03BA\u03C1\u03B9\u03C3\u03B7
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=\u03A5\u03C0\u03BF\u03B3\u03C1\u03B1\u03C6\u03AE sign.title=\u03A5\u03C0\u03BF\u03B3\u03C1\u03B1\u03C6\u03AE
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=????????? PDFToCSV.submit=?????????
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Split PDF by Size or Count split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size split-by-size-or-count.type.size=By Size
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr = left to right, rtl = right to left) # the direction that the language is written (ltr = left to right, rtl = right to left)
@@ -17,9 +17,11 @@ true=True
false=False false=False
unknown=Unknown unknown=Unknown
save=Save save=Save
saveToBrowser=Save to Browser
close=Close close=Close
filesSelected=files selected filesSelected=files selected
noFavourites=No favourites added noFavourites=No favourites added
downloadComplete=Download Complete
bored=Bored Waiting? bored=Bored Waiting?
alphabet=Alphabet alphabet=Alphabet
downloadPdf=Download PDF downloadPdf=Download PDF
@@ -52,12 +54,15 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -107,7 +112,7 @@ settings.accountSettings=Account Settings
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -142,13 +147,16 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User adminUserSettings.apiUser=Limited API User
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Web Only User adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange = Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
############# #############
@@ -392,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -399,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Sign in login.title=Sign in
login.header=Sign in
login.signin=Sign in login.signin=Sign in
login.rememberme=Remember me login.rememberme=Remember me
login.invalid=Invalid username or password. login.invalid=Invalid username or password.
@@ -623,6 +641,18 @@ compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Compare compare.submit=Compare
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Sign sign.title=Sign
@@ -925,6 +955,7 @@ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=Extract PDFToCSV.submit=Extract
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Split PDF by Size or Count split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size split-by-size-or-count.type.size=By Size
@@ -959,7 +990,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=Select Image(s)
genericSubmit=Submit genericSubmit=Submit
processTimeWarning=Warning: This process can take up to a minute depending on file-size processTimeWarning=Warning: This process can take up to a minute depending on file-size
pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) : pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Go goToPage=Go
true=True true=True
false=False false=False
unknown=Unknown unknown=Unknown
save=Save save=Save
saveToBrowser=Save to Browser
close=Close close=Close
filesSelected=files selected filesSelected=files selected
noFavourites=No favorites added noFavourites=No favorites added
downloadComplete=Download Complete
bored=Bored Waiting? bored=Bored Waiting?
alphabet=Alphabet alphabet=Alphabet
downloadPdf=Download PDF downloadPdf=Download PDF
@@ -51,12 +54,15 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=Account Settings
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -141,13 +147,16 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User adminUserSettings.apiUser=Limited API User
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Web Only User adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
############# #############
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Sign in login.title=Sign in
login.header=Sign in
login.signin=Sign in login.signin=Sign in
login.rememberme=Remember me login.rememberme=Remember me
login.invalid=Invalid username or password. login.invalid=Invalid username or password.
@@ -622,6 +641,18 @@ compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Compare compare.submit=Compare
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Sign sign.title=Sign
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=Extract PDFToCSV.submit=Extract
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Split PDF by Size or Count split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size split-by-size-or-count.type.size=By Size
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=Seleccionar Imagen(es)
genericSubmit=Enviar genericSubmit=Enviar
processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo
pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma): pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma):
pageSelectionPrompt=Selección de página personalizada (Intruduzca una lista de números de página separados por comas 1,5,6 o funciones como 2n+1) :
goToPage=Ir a goToPage=Ir a
true=Verdadero true=Verdadero
false=Falso false=Falso
unknown=Desconocido unknown=Desconocido
save=Guardar save=Guardar
saveToBrowser=Save to Browser
close=Cerrar close=Cerrar
filesSelected=archivos seleccionados filesSelected=archivos seleccionados
noFavourites=No se agregaron favoritos noFavourites=No se agregaron favoritos
downloadComplete=Download Complete
bored=¿Cansado de esperar? bored=¿Cansado de esperar?
alphabet=Alfabeto alphabet=Alfabeto
downloadPdf=Descargar PDF downloadPdf=Descargar PDF
@@ -51,12 +54,15 @@ notAuthenticatedMessage=Usuario no autentificado.
userNotFoundMessage=Usuario no encontrado. userNotFoundMessage=Usuario no encontrado.
incorrectPasswordMessage=La contraseña actual no es correcta. incorrectPasswordMessage=La contraseña actual no es correcta.
usernameExistsMessage=El nuevo nombre de usuario está en uso. usernameExistsMessage=El nuevo nombre de usuario está en uso.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Menu Pipeline (Alfa) pipeline.header=Menú de canalización (Alfa)
pipeline.uploadButton=Cargar personalización pipeline.uploadButton=Cargar personalización
pipeline.configureButton=Configurar pipeline.configureButton=Configurar
pipeline.defaultOption=Personalizar pipeline.defaultOption=Personalizar
@@ -65,13 +71,13 @@ pipeline.submitButton=Enviar
###################### ######################
# Pipeline Options # # Pipeline Options #
###################### ######################
pipelineOptions.header=Configuración Pipeline pipelineOptions.header=Configuración de la canalización
pipelineOptions.pipelineNameLabel=Nombre del Pipeline pipelineOptions.pipelineNameLabel=Nombre de la canalización
pipelineOptions.saveSettings=Guardar configuración de la oiperación pipelineOptions.saveSettings=Guardar configuración de la canalización
pipelineOptions.pipelineNamePrompt=Introduzca aquí el nombre del pipeline pipelineOptions.pipelineNamePrompt=Introduzca aquí el nombre de la canalización
pipelineOptions.selectOperation=Seleccione la operación pipelineOptions.selectOperation=Seleccione la operación
pipelineOptions.addOperationButton=Añadir operación pipelineOptions.addOperationButton=Añadir operación
pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.pipelineHeader=Canalización:
pipelineOptions.saveButton=Descargar pipelineOptions.saveButton=Descargar
pipelineOptions.validateButton=Validar pipelineOptions.validateButton=Validar
@@ -106,7 +112,7 @@ settings.accountSettings=Configuración de la cuenta
changeCreds.title=Cambiar Credenciales changeCreds.title=Cambiar Credenciales
changeCreds.header=Actualice los detalles de su cuenta changeCreds.header=Actualice los detalles de su cuenta
changeCreds.changeUserAndPassword=Está usando las credenciales por defecto. Por favor, introduzca una nueva contraseña (y usuario si lo desea) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Nuevo usuario changeCreds.newUsername=Nuevo usuario
changeCreds.oldPassword=Contraseña actual changeCreds.oldPassword=Contraseña actual
changeCreds.newPassword=Nueva contraseña changeCreds.newPassword=Nueva contraseña
@@ -141,12 +147,15 @@ adminUserSettings.header=Configuración de control de usuario administrador
adminUserSettings.admin=Administrador adminUserSettings.admin=Administrador
adminUserSettings.user=Usuario adminUserSettings.user=Usuario
adminUserSettings.addUser=Añadir Nuevo Usuario adminUserSettings.addUser=Añadir Nuevo Usuario
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Acciones adminUserSettings.actions=Acciones
adminUserSettings.apiUser=Usuario limitado de API adminUserSettings.apiUser=Usuario limitado de API
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Usuario solo web adminUserSettings.webOnlyUser=Usuario solo web
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso
adminUserSettings.submit=Guardar Usuario adminUserSettings.submit=Guardar Usuario
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Iniciar sesión login.title=Iniciar sesión
login.header=Iniciar sesión
login.signin=Iniciar sesión login.signin=Iniciar sesión
login.rememberme=Recordarme login.rememberme=Recordarme
login.invalid=Nombre de usuario o contraseña erróneos. login.invalid=Nombre de usuario o contraseña erróneos.
@@ -562,7 +581,7 @@ autoSplitPDF.submit=Entregar
#pipeline #pipeline
pipeline.title=Pipeline pipeline.title=Canalización
#pageLayout #pageLayout
@@ -622,6 +641,18 @@ compare.document.1=Documento 1
compare.document.2=Documento 2 compare.document.2=Documento 2
compare.submit=Comparar compare.submit=Comparar
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Firmar sign.title=Firmar
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Elija una página para extraer la tabla
PDFToCSV.submit=Extraer PDFToCSV.submit=Extraer
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Dividir PDF por tamaño o número split-by-size-or-count.header=Dividir PDF por tamaño o número
split-by-size-or-count.type.label=Seleccionar tipo de división split-by-size-or-count.type.label=Seleccionar tipo de división
split-by-size-or-count.type.size=Por tamaño split-by-size-or-count.type.size=Por tamaño
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Divisiones Verticales
split-by-sections.horizontal.placeholder=Introduzca el número de divisiones horizontales split-by-sections.horizontal.placeholder=Introduzca el número de divisiones horizontales
split-by-sections.vertical.placeholder=Introduzca el número de divisiones verticales split-by-sections.vertical.placeholder=Introduzca el número de divisiones verticales
split-by-sections.submit=Dividir PDF split-by-sections.submit=Dividir PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licencias licenses.nav=Licencias

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=Hautatu Irudia(k)
genericSubmit=Bidali genericSubmit=Bidali
processTimeWarning=Oharra: prozesu honetarako minutu bat ere beharko da fitxategiaren tamaiaren arabera processTimeWarning=Oharra: prozesu honetarako minutu bat ere beharko da fitxategiaren tamaiaren arabera
pageOrderPrompt=Orrialdeen ordena (sartu komaz bereizitako orrialde-zenbakien zerrenda) pageOrderPrompt=Orrialdeen ordena (sartu komaz bereizitako orrialde-zenbakien zerrenda)
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Joan goToPage=Joan
true=Egiazkoa true=Egiazkoa
false=Faltsua false=Faltsua
unknown=Ezezaguna unknown=Ezezaguna
save=Gorde save=Gorde
saveToBrowser=Save to Browser
close=Itxi close=Itxi
filesSelected=Hautatutako fitxategiak filesSelected=Hautatutako fitxategiak
noFavourites=Ez dira gogokoak gehitu noFavourites=Ez dira gogokoak gehitu
downloadComplete=Download Complete
bored=Itxaroten aspertuta? bored=Itxaroten aspertuta?
alphabet=Alfabetoa alphabet=Alfabetoa
downloadPdf=PDFa deskargatu downloadPdf=PDFa deskargatu
@@ -51,12 +54,15 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=Kontuaren ezarpenak
changeCreds.title=Change Credentials changeCreds.title=Change Credentials
changeCreds.header=Update Your Account Details changeCreds.header=Update Your Account Details
changeCreds.changeUserAndPassword=You are using default login credentials. Please enter a new password (and username if wanted) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=New Username changeCreds.newUsername=New Username
changeCreds.oldPassword=Current Password changeCreds.oldPassword=Current Password
changeCreds.newPassword=New Password changeCreds.newPassword=New Password
@@ -141,13 +147,16 @@ adminUserSettings.header=Admin Erabiltzailearen Ezarpenen Kontrolak
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Erabiltzaile adminUserSettings.user=Erabiltzaile
adminUserSettings.addUser=Erabiltzaile berria adminUserSettings.addUser=Erabiltzaile berria
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Rolak adminUserSettings.roles=Rolak
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Ekintzak adminUserSettings.actions=Ekintzak
adminUserSettings.apiUser=APIren erabiltzaile mugatua adminUserSettings.apiUser=APIren erabiltzaile mugatua
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Web-erabiltzailea bakarrik adminUserSettings.webOnlyUser=Web-erabiltzailea bakarrik
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Gorde Erabiltzailea adminUserSettings.submit=Gorde Erabiltzailea
############# #############
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Saioa hasi login.title=Saioa hasi
login.header=Saioa hasi
login.signin=Saioa hasi login.signin=Saioa hasi
login.rememberme=Oroitu nazazu login.rememberme=Oroitu nazazu
login.invalid=Okerreko erabiltzaile izena edo pasahitza. login.invalid=Okerreko erabiltzaile izena edo pasahitza.
@@ -622,6 +641,18 @@ compare.document.1=1. dokumentua
compare.document.2=2. dokumentua compare.document.2=2. dokumentua
compare.submit=Konparatu compare.submit=Konparatu
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Sinatu sign.title=Sinatu
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=Extracto PDFToCSV.submit=Extracto
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Split PDF by Size or Count split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size split-by-size-or-count.type.size=By Size
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=Choisir une image
genericSubmit=Envoyer genericSubmit=Envoyer
processTimeWarning=Attention, ce processus peut prendre jusqu\u2019à une minute en fonction de la taille du fichier. processTimeWarning=Attention, ce processus peut prendre jusqu\u2019à une minute en fonction de la taille du fichier.
pageOrderPrompt=Ordre des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0: pageOrderPrompt=Ordre des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0:
pageSelectionPrompt=Sélection des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0:
goToPage=Aller goToPage=Aller
true=Vrai true=Vrai
false=Faux false=Faux
unknown=Inconnu unknown=Inconnu
save=Enregistrer save=Enregistrer
saveToBrowser=Save to Browser
close=Fermer close=Fermer
filesSelected=fichiers sélectionnés filesSelected=fichiers sélectionnés
noFavourites=Aucun favori ajouté noFavourites=Aucun favori ajouté
downloadComplete=Téléchargement terminé
bored=Ennuyé d\u2019attendre\u00a0? bored=Ennuyé d\u2019attendre\u00a0?
alphabet=Alphabet alphabet=Alphabet
downloadPdf=Télécharger le PDF downloadPdf=Télécharger le PDF
@@ -42,38 +45,41 @@ red=Rouge
green=Vert green=Vert
blue=Bleu blue=Bleu
custom=Personnalisé\u2026 custom=Personnalisé\u2026
WorkInProgess=Work in progress, May not work or be buggy, Please report any problems! WorkInProgess=En cours de développement, merci de nous remonter les problèmes que vous pourriez constater!
poweredBy=Powered by poweredBy=Propulsé par
yes=Yes yes=Oui
no=No no=Non
changedCredsMessage=Les identifiants ont été mis à jour\u00a0! changedCredsMessage=Les identifiants ont été mis à jour\u00a0!
notAuthenticatedMessage=Utilisateur non authentifié. notAuthenticatedMessage=Utilisateur non authentifié.
userNotFoundMessage=Utilisateur non trouvé. userNotFoundMessage=Utilisateur non trouvé.
incorrectPasswordMessage=Le mot de passe actuel est incorrect. incorrectPasswordMessage=Le mot de passe actuel est incorrect.
usernameExistsMessage=Le nouveau nom d\u2019utilisateur existe déjà. usernameExistsMessage=Le nouveau nom d\u2019utilisateur existe déjà.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Menu Pipeline (Alpha)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Télécharger une personnalisation
pipeline.configureButton=Configure pipeline.configureButton=Configurer
pipeline.defaultOption=Custom pipeline.defaultOption=Personnaliser
pipeline.submitButton=Submit pipeline.submitButton=Soumettre
###################### ######################
# Pipeline Options # # Pipeline Options #
###################### ######################
pipelineOptions.header=Pipeline Configuration pipelineOptions.header=Configuration du pipeline
pipelineOptions.pipelineNameLabel=Pipeline Name pipelineOptions.pipelineNameLabel=Nom du pipeline
pipelineOptions.saveSettings=Save Operation Settings pipelineOptions.saveSettings=Sauvegarder la configuration
pipelineOptions.pipelineNamePrompt=Enter pipeline name here pipelineOptions.pipelineNamePrompt=Entrez ici le nom du pipeline
pipelineOptions.selectOperation=Select Operation pipelineOptions.selectOperation=Sélectionner une opération
pipelineOptions.addOperationButton=Add operation pipelineOptions.addOperationButton=Ajouter une opération
pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download pipelineOptions.saveButton=Télécharger
pipelineOptions.validateButton=Validate pipelineOptions.validateButton=Valider
@@ -106,7 +112,7 @@ settings.accountSettings=Paramètres du compte
changeCreds.title=Modifiez vos identifiants changeCreds.title=Modifiez vos identifiants
changeCreds.header=Mettez à jour vos identifiants de connexion changeCreds.header=Mettez à jour vos identifiants de connexion
changeCreds.changeUserAndPassword=Vous utilisez les identifiants de connexion par défaut. Veuillez entrer un nouveau mot de passe (et nom d\u2019utilisateur si vous le souhaitez) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Nouveau nom d\u2019utilisateur changeCreds.newUsername=Nouveau nom d\u2019utilisateur
changeCreds.oldPassword=Mot de passe actuel changeCreds.oldPassword=Mot de passe actuel
changeCreds.newPassword=Nouveau mot de passe changeCreds.newPassword=Nouveau mot de passe
@@ -141,12 +147,15 @@ adminUserSettings.header=Administration des paramètres des utilisateurs
adminUserSettings.admin=Administateur adminUserSettings.admin=Administateur
adminUserSettings.user=Utilisateur adminUserSettings.user=Utilisateur
adminUserSettings.addUser=Ajouter un utilisateur adminUserSettings.addUser=Ajouter un utilisateur
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Rôles adminUserSettings.roles=Rôles
adminUserSettings.role=Rôle adminUserSettings.role=Rôle
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Utilisateur API limité adminUserSettings.apiUser=Utilisateur API limité
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Utilisateur Web uniquement adminUserSettings.webOnlyUser=Utilisateur Web uniquement
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (Paramètres par défaut)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Forcer l\u2019utilisateur à changer son nom d\u2019utilisateur/mot de passe lors de la connexion adminUserSettings.forceChange=Forcer l\u2019utilisateur à changer son nom d\u2019utilisateur/mot de passe lors de la connexion
adminUserSettings.submit=Ajouter adminUserSettings.submit=Ajouter
@@ -158,7 +167,7 @@ home.searchBar=Rechercher des fonctionnalités...
home.viewPdf.title=Visionner le PDF home.viewPdf.title=Visionner le PDF
home.viewPdf.desc=Visionner, annoter, ajouter du texte ou des images home.viewPdf.desc=Visionner, annoter, ajouter du texte ou des images.
viewPdf.tags=visualiser,lire,annoter,texte,image viewPdf.tags=visualiser,lire,annoter,texte,image
home.multiTool.title=Outil multifonction PDF home.multiTool.title=Outil multifonction PDF
@@ -167,7 +176,7 @@ multiTool.tags=outil multifonction,opération multifonction,interface utilisateu
home.merge.title=Fusionner home.merge.title=Fusionner
home.merge.desc=Fusionnez facilement plusieurs PDF en un seul. home.merge.desc=Fusionnez facilement plusieurs PDF en un seul.
merge.tags=fusionner,opérations sur les pages,backeend,server side,merge merge.tags=fusionner,opérations sur les pages,backend,server side,merge
home.split.title=Diviser home.split.title=Diviser
home.split.desc=Divisez un PDF en plusieurs documents. home.split.desc=Divisez un PDF en plusieurs documents.
@@ -283,9 +292,9 @@ home.removeBlanks.title=Supprimer les pages vierges
home.removeBlanks.desc=Détectez et supprimez les pages vierges d\u2019un PDF. home.removeBlanks.desc=Détectez et supprimez les pages vierges d\u2019un PDF.
removeBlanks.tags=pages vierges,supprimer,nettoyer,cleanup,streamline,non-content,organize removeBlanks.tags=pages vierges,supprimer,nettoyer,cleanup,streamline,non-content,organize
home.removeAnnotations.title=Remove Annotations home.removeAnnotations.title=Supprimer les annotations
home.removeAnnotations.desc=Removes all comments/annotations from a PDF home.removeAnnotations.desc=Supprimer tous les commentaires/annotations d\u2019un PDF.
removeAnnotations.tags=comments,highlight,notes,markup,remove removeAnnotations.tags=commentaires,supprimer,annotations,highlight,notes,markup,remove
home.compare.title=Comparer home.compare.title=Comparer
home.compare.desc=Comparez et visualisez les différences entre deux PDF. home.compare.desc=Comparez et visualisez les différences entre deux PDF.
@@ -369,7 +378,7 @@ home.autoRedact.desc=Caviardez automatiquement les informations sensibles d\u201
autoRedact.tags=caviarder,redact,auto autoRedact.tags=caviarder,redact,auto
home.tableExtraxt.title=PDF en CSV home.tableExtraxt.title=PDF en CSV
home.tableExtraxt.desc=Extrait les tableaux d\u2019un PDF et les transforme en CSV home.tableExtraxt.desc=Extrait les tableaux d\u2019un PDF et les transforme en CSV.
tableExtraxt.tags=CSV,Table Extraction,extract,convert tableExtraxt.tags=CSV,Table Extraction,extract,convert
@@ -379,16 +388,25 @@ autoSizeSplitPDF.tags=pdf,split,document,organization
home.overlay-pdfs.title=Incrustation de PDF home.overlay-pdfs.title=Incrustation de PDF
home.overlay-pdfs.desc=Incrustation d\u2019un PDF sur un autre PDF home.overlay-pdfs.desc=Incrustation d\u2019un PDF sur un autre PDF.
overlay-pdfs.tags=Overlay overlay-pdfs.tags=Overlay,incrustation
home.split-by-sections.title=Split PDF by Sections home.split-by-sections.title=Séparer un PDF en sections
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections home.split-by-sections.desc=Diviser chaque page d\u2019un PDF en sections horizontales/verticales plus petites.
split-by-sections.tags=Section Split, Divide, Customize split-by-sections.tags=Sections,Diviser,Section Split, Divide, Customize
home.AddStampRequest.title=Add Stamp to PDF home.AddStampRequest.title=Ajouter un tampon sur un PDF
home.AddStampRequest.desc=Add text or add image stamps at set locations home.AddStampRequest.desc=Ajouter un texte ou l\u2019image d\u2019un tampon à un emplacement défini.
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Tampon,Ajouter,Stamp,Add image,center image,Watermark,PDF,Embed,Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Connexion login.title=Connexion
login.header=Connexion
login.signin=Connexion login.signin=Connexion
login.rememberme=Se souvenir de moi login.rememberme=Se souvenir de moi
login.invalid=Nom d\u2019utilisateur ou mot de passe invalide. login.invalid=Nom d\u2019utilisateur ou mot de passe invalide.
@@ -466,37 +485,37 @@ HTMLToPDF.header=HTML en PDF
HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis). HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis).
HTMLToPDF.submit=Convertir HTMLToPDF.submit=Convertir
HTMLToPDF.credit=Utilise WeasyPrint. HTMLToPDF.credit=Utilise WeasyPrint.
HTMLToPDF.zoom=Zoom level for displaying the website. HTMLToPDF.zoom=Niveau de zoom pour l\u2019affichage du site web.
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default) HTMLToPDF.pageWidth=Largeur de la page en centimètres. (Vide par défaut)
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default) HTMLToPDF.pageHeight=Hauteur de la page en centimètres. (Vide par défaut)
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default) HTMLToPDF.marginTop=Marge supérieure de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default) HTMLToPDF.marginBottom=Marge inférieure de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default) HTMLToPDF.marginLeft=Marge gauche de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default) HTMLToPDF.marginRight=Marge droite de la page en millimètres. (Vide par défaut)
HTMLToPDF.printBackground=Render the background of websites. HTMLToPDF.printBackground=Restituer l\u2019image de fond des sites web.
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number) HTMLToPDF.defaultHeader=Activer l\u2019entête par défaut (Nom et numéro de page)
HTMLToPDF.cssMediaType=Change the CSS media type of the page. HTMLToPDF.cssMediaType=Modifier le type de média CSS de la page.
HTMLToPDF.none=None HTMLToPDF.none=Aucun
HTMLToPDF.print=Print HTMLToPDF.print=Imprimer
HTMLToPDF.screen=Screen HTMLToPDF.screen=Écran
#AddStampRequest #AddStampRequest
AddStampRequest.header=Stamp PDF AddStampRequest.header=Tampon PDF
AddStampRequest.title=Stamp PDF AddStampRequest.title=Tampon PDF
AddStampRequest.stampType=Stamp Type AddStampRequest.stampType=Type de tampon
AddStampRequest.stampText=Stamp Text AddStampRequest.stampText=Tampon texte
AddStampRequest.stampImage=Stamp Image AddStampRequest.stampImage=Tampon image
AddStampRequest.alphabet=Alphabet AddStampRequest.alphabet=Alphabet
AddStampRequest.fontSize=Font/Image Size AddStampRequest.fontSize=Taille de fonte/image
AddStampRequest.rotation=Rotation AddStampRequest.rotation=Rotation
AddStampRequest.opacity=Opacity AddStampRequest.opacity=Opacité
AddStampRequest.position=Position AddStampRequest.position=Position
AddStampRequest.overrideX=Override X Coordinate AddStampRequest.overrideX=Définir coordonnées X
AddStampRequest.overrideY=Override Y Coordinate AddStampRequest.overrideY=Définir coordonnées Y
AddStampRequest.customMargin=Custom Margin AddStampRequest.customMargin=Marge personnalisée
AddStampRequest.customColor=Custom Text Color AddStampRequest.customColor=Couleur de texte personnalisée
AddStampRequest.submit=Submit AddStampRequest.submit=Soumettre
#sanitizePDF #sanitizePDF
@@ -585,11 +604,11 @@ scalePages.submit=Ajuster
certSign.title=Signer avec un certificat certSign.title=Signer avec un certificat
certSign.header=Signer avec un certificat (Travail en cours) certSign.header=Signer avec un certificat (Travail en cours)
certSign.selectPDF=PDF à signer certSign.selectPDF=PDF à signer
certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below. certSign.jksNote=Note: Si votre type de certificat n\u2019est pas listé ci\u002Ddessous, merci de le convertir en fichier Java Keystore (.jks) en utilisant l\u2019outil en ligne de commande keytool. Puis choisissez l\u2019option Fichier .jks ci\u002Ddessous.
certSign.selectKey=Fichier de clé privée (format PKCS#8, peut être .pem ou .der) certSign.selectKey=Fichier de clé privée (format PKCS#8, peut être .pem ou .der)
certSign.selectCert=Fichier de certificat (format X.509, peut être .pem ou .der) certSign.selectCert=Fichier de certificat (format X.509, peut être .pem ou .der)
certSign.selectP12=Fichier keystore de clés PKCS#12 (.p12 ou .pfx) (facultatif, s\u2019il n\u2019est fourni, il doit contenir votre clé privée et votre certificat) certSign.selectP12=Fichier keystore de clés PKCS#12 (.p12 ou .pfx) (facultatif, s\u2019il n\u2019est fourni, il doit contenir votre clé privée et votre certificat)
certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore): certSign.selectJKS=Sélectionner votre fichier Java Keystore File (.jks or .keystore):
certSign.certType=Type de certificat certSign.certType=Type de certificat
certSign.password=Mot de passe keystore ou clé privée le cas échéant certSign.password=Mot de passe keystore ou clé privée le cas échéant
certSign.showSig=Afficher la signature certSign.showSig=Afficher la signature
@@ -610,9 +629,9 @@ removeBlanks.submit=Supprimer les pages vierges
#removeAnnotations #removeAnnotations
removeAnnotations.title=Remove Annotations removeAnnotations.title=Supprimer les annotations
removeAnnotations.header=Remove Annotations removeAnnotations.header=Supprimer les annotations
removeAnnotations.submit=Remove removeAnnotations.submit=Supprimer
#compare #compare
@@ -622,6 +641,18 @@ compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Comparer compare.submit=Comparer
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Signer sign.title=Signer
@@ -694,14 +725,14 @@ fileToPDF.submit=Convertir
#compress #compress
compress.title=Compresser compress.title=Compresser un PDF
compress.header=Compresser compress.header=Compresser un PDF (lorsque c\u2019est possible!)
compress.credit=Ce service utilise Ghostscript pour la compression et l\u2019optimisation des PDF. compress.credit=Ce service utilise Ghostscript pour la compression et l\u2019optimisation des PDF.
compress.selectText.1=Mode manuel \u2013 de 1 à 4 compress.selectText.1=Mode manuel \u2013 de 1 à 4
compress.selectText.2=Niveau d\u2019optimisation compress.selectText.2=Niveau d\u2019optimisation
compress.selectText.3=4 (terrible pour les images textuelles) compress.selectText.3=4 (terrible pour les images textuelles)
compress.selectText.4=Mode automatique \u2013 ajuste automatiquement la qualité pour obtenir le PDF à la taille exacte compress.selectText.4=Mode automatique \u2013 ajuste automatiquement la qualité pour obtenir le PDF à la taille exacte
compress.selectText.5=Taille PDF attendue (par exemple, 25\u202fMo, 10,8\u202fMo, 25\u202fKo) compress.selectText.5=Taille PDF attendue (par exemple, 25\u202fMB, 10,8\u202fMB, 25\u202fKB)
compress.submit=Compresser compress.submit=Compresser
@@ -732,8 +763,8 @@ multiTool.title=Outil multifonction PDF
multiTool.header=Outil multifonction PDF multiTool.header=Outil multifonction PDF
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=Visualiser un PDF
viewPdf.header=View PDF viewPdf.header=Visualiser un PDF
#pageRemover #pageRemover
pageRemover.title=Supprimer des pages pageRemover.title=Supprimer des pages
@@ -788,7 +819,7 @@ pdfToImage.multi=Plusieurs images
pdfToImage.colorType=Type d\u2019impression pdfToImage.colorType=Type d\u2019impression
pdfToImage.color=Couleur pdfToImage.color=Couleur
pdfToImage.grey=Niveaux de gris pdfToImage.grey=Niveaux de gris
pdfToImage.blackwhite=Noir et blanc (peut engendre une perde de données\u00a0!) pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données\u00a0!)
pdfToImage.submit=Convertir pdfToImage.submit=Convertir
@@ -867,7 +898,7 @@ changeMetadata.keywords=Mots clés
changeMetadata.modDate=Date de modification (yyyy/MM/dd HH:mm:ss) changeMetadata.modDate=Date de modification (yyyy/MM/dd HH:mm:ss)
changeMetadata.producer=Producteur changeMetadata.producer=Producteur
changeMetadata.subject=Sujet changeMetadata.subject=Sujet
changeMetadata.trapped=Défoncé (technique dimpression) changeMetadata.trapped=Recouvrement (technique dimpression)
changeMetadata.selectText.4=Autres métadonnées changeMetadata.selectText.4=Autres métadonnées
changeMetadata.selectText.5=Ajouter une entrée de métadonnées personnalisée changeMetadata.selectText.5=Ajouter une entrée de métadonnées personnalisée
changeMetadata.submit=Modifier changeMetadata.submit=Modifier
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Choisir la page pour en extraire le tableau
PDFToCSV.submit=Extrait PDFToCSV.submit=Extrait
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Séparer le PDF par taille ou par nombre
split-by-size-or-count.header=Séparer le PDF par taille ou par nombre split-by-size-or-count.header=Séparer le PDF par taille ou par nombre
split-by-size-or-count.type.label=Sélectionner le type de division split-by-size-or-count.type.label=Sélectionner le type de division
split-by-size-or-count.type.size=Par taille split-by-size-or-count.type.size=Par taille
@@ -935,19 +967,19 @@ split-by-size-or-count.submit=Séparer
#overlay-pdfs #overlay-pdfs
overlay-pdfs.header=Overlay PDF Files overlay-pdfs.header=Incrustation de PDF
overlay-pdfs.baseFile.label=Sélectionner le fichier PDF de base overlay-pdfs.baseFile.label=Sélectionner le fichier PDF de base
overlay-pdfs.overlayFiles.label=Sélectionner les fichiers PDF à superposer overlay-pdfs.overlayFiles.label=Sélectionner les fichiers PDF à superposer
overlay-pdfs.mode.label=Select Overlay Mode overlay-pdfs.mode.label=Sélectionner le mode d\u2019incrustation
overlay-pdfs.mode.sequential=Sequential Overlay overlay-pdfs.mode.sequential=Superposition séquentielle
overlay-pdfs.mode.interleaved=Interleaved Overlay overlay-pdfs.mode.interleaved=Superposition entrelacée
overlay-pdfs.mode.fixedRepeat=Superposition à répétition fixe overlay-pdfs.mode.fixedRepeat=Superposition à répétition fixe
overlay-pdfs.counts.label=Nombre de superpositions (pour le mode de répétition fixe) overlay-pdfs.counts.label=Nombre de superpositions (pour le mode de répétition fixe)
overlay-pdfs.counts.placeholder=Enter comma-separated counts (e.g., 2,3,1) overlay-pdfs.counts.placeholder=Compteurs (séparés par des virgules, exemple : 2,3,1)
overlay-pdfs.position.label=Select Overlay Position overlay-pdfs.position.label=Définir la position de l\u2019incrustation
overlay-pdfs.position.foreground=Premier plan overlay-pdfs.position.foreground=Premier plan
overlay-pdfs.position.background=Arrière-plan overlay-pdfs.position.background=Arrière-plan
overlay-pdfs.submit=Submit overlay-pdfs.submit=Soumettre
#split-by-sections #split-by-sections
@@ -958,14 +990,14 @@ split-by-sections.vertical.label=Divisions verticales
split-by-sections.horizontal.placeholder=Saisir le nombre de divisions horizontales split-by-sections.horizontal.placeholder=Saisir le nombre de divisions horizontales
split-by-sections.vertical.placeholder=Entrer le nombre de divisions verticales split-by-sections.vertical.placeholder=Entrer le nombre de divisions verticales
split-by-sections.submit=Diviser le PDF split-by-sections.submit=Diviser le PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licences
licenses.title=3rd Party Licenses licenses.title=Licences tierces
licenses.header=3rd Party Licenses licenses.header=Licences tierces
licenses.module=Module licenses.module=Module
licenses.version=Version licenses.version=Version
licenses.license=License licenses.license=Licence

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=छवियों का चयन करें
genericSubmit=प्रस्तुत करें genericSubmit=प्रस्तुत करें
processTimeWarning=चेतावनी: यह प्रक्रिया फ़ाइल के आकार पर निर्भर करती है और यह से एक मिनट तक लग सकती है processTimeWarning=चेतावनी: यह प्रक्रिया फ़ाइल के आकार पर निर्भर करती है और यह से एक मिनट तक लग सकती है
pageOrderPrompt=कस्टम पेज क्रम (पेज नंबरों या 2n+1 जैसे कार्यों की एक कॉमा से अलग-अलग सूची दर्ज करें): pageOrderPrompt=कस्टम पेज क्रम (पेज नंबरों या 2n+1 जैसे कार्यों की एक कॉमा से अलग-अलग सूची दर्ज करें):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=जाएँ goToPage=जाएँ
true=सही true=सही
false=गलत false=गलत
unknown=अज्ञात unknown=अज्ञात
save=सहेजें save=सहेजें
saveToBrowser=Save to Browser
close=बंद करें close=बंद करें
filesSelected=फ़ाइलें चयनित हैं filesSelected=फ़ाइलें चयनित हैं
noFavourites=कोई पसंदीदा जोड़ा नहीं गया है noFavourites=कोई पसंदीदा जोड़ा नहीं गया है
downloadComplete=Download Complete
bored=बोर हो रहे हैं? bored=बोर हो रहे हैं?
alphabet=वर्णमाला alphabet=वर्णमाला
downloadPdf=पीडीएफ़ डाउनलोड करें downloadPdf=पीडीएफ़ डाउनलोड करें
@@ -51,12 +54,15 @@ notAuthenticatedMessage=उपयोगकर्ता प्रमाणित
userNotFoundMessage=उपयोगकर्ता नहीं मिला। userNotFoundMessage=उपयोगकर्ता नहीं मिला।
incorrectPasswordMessage=वर्तमान पासवर्ड गलत है। incorrectPasswordMessage=वर्तमान पासवर्ड गलत है।
usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है। usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है।
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=खाता सेटिंग्स
changeCreds.title=क्रेडेंशियल बदलें changeCreds.title=क्रेडेंशियल बदलें
changeCreds.header=अपना खाता विवरण अपडेट करें changeCreds.header=अपना खाता विवरण अपडेट करें
changeCreds.changeUserAndPassword=आप डिफ़ॉल्ट लॉगिन क्रेडेंशियल का उपयोग कर रहे हैं। कृपया एक नया पासवर्ड दर्ज करें (और यदि चाहें तो उपयोगकर्ता नाम) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=नया उपयोगकर्ता नाम changeCreds.newUsername=नया उपयोगकर्ता नाम
changeCreds.oldPassword=वर्तमान पासवर्ड changeCreds.oldPassword=वर्तमान पासवर्ड
changeCreds.newPassword=नया पासवर्ड changeCreds.newPassword=नया पासवर्ड
@@ -141,12 +147,15 @@ adminUserSettings.header=व्यवस्थापक उपयोगकर्
adminUserSettings.admin=व्यवस्थापक adminUserSettings.admin=व्यवस्थापक
adminUserSettings.user=उपयोगकर्ता adminUserSettings.user=उपयोगकर्ता
adminUserSettings.addUser=नया उपयोगकर्ता जोड़ें adminUserSettings.addUser=नया उपयोगकर्ता जोड़ें
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=रोल्स adminUserSettings.roles=रोल्स
adminUserSettings.role=रोल adminUserSettings.role=रोल
adminUserSettings.actions=क्रियाएँ adminUserSettings.actions=क्रियाएँ
adminUserSettings.apiUser=सीमित API उपयोगकर्ता adminUserSettings.apiUser=सीमित API उपयोगकर्ता
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=केवल वेब उपयोगकर्ता adminUserSettings.webOnlyUser=केवल वेब उपयोगकर्ता
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=उपयोगकर्ता को लॉगिन पर उपयोगकर्ता नाम/पासवर्ड बदलने के लिए मजबूर करें adminUserSettings.forceChange=उपयोगकर्ता को लॉगिन पर उपयोगकर्ता नाम/पासवर्ड बदलने के लिए मजबूर करें
adminUserSettings.submit=उपयोगकर्ता को सहेजें adminUserSettings.submit=उपयोगकर्ता को सहेजें
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=साइन इन करें login.title=साइन इन करें
login.header=साइन इन करें
login.signin=साइन इन करें login.signin=साइन इन करें
login.rememberme=मुझे याद रखें login.rememberme=मुझे याद रखें
login.invalid=अमान्य उपयोगकर्ता नाम या पासवर्ड। login.invalid=अमान्य उपयोगकर्ता नाम या पासवर्ड।
@@ -622,6 +641,18 @@ compare.document.1=दस्तावेज़ 1
compare.document.2=दस्तावेज़ 2 compare.document.2=दस्तावेज़ 2
compare.submit=तुलना करें compare.submit=तुलना करें
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=हस्ताक्षर sign.title=हस्ताक्षर
@@ -924,6 +955,7 @@ PDFToCSV.prompt=टेबल निकालने के लिए पृष्
PDFToCSV.submit=निकालें PDFToCSV.submit=निकालें
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=आकार या गणना द्वारा PDF को विभाजित करें
split-by-size-or-count.header=आकार या गणना द्वारा PDF को विभाजित करें split-by-size-or-count.header=आकार या गणना द्वारा PDF को विभाजित करें
split-by-size-or-count.type.label=स्प्लिट प्रकार चुनें split-by-size-or-count.type.label=स्प्लिट प्रकार चुनें
split-by-size-or-count.type.size=आकार द्वारा split-by-size-or-count.type.size=आकार द्वारा
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=लंबवत विभाजन
split-by-sections.horizontal.placeholder=क्षैतिज विभाजन की संख्या दर्ज करें split-by-sections.horizontal.placeholder=क्षैतिज विभाजन की संख्या दर्ज करें
split-by-sections.vertical.placeholder=लंबवत विभाजन की संख्या दर्ज करें split-by-sections.vertical.placeholder=लंबवत विभाजन की संख्या दर्ज करें
split-by-sections.submit=PDF को विभाजित करें split-by-sections.submit=PDF को विभाजित करें
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=Válasszon képeket
genericSubmit=Beküldés genericSubmit=Beküldés
processTimeWarning=Figyelmeztetés: Ez a folyamat akár egy percig is eltarthat a fájlmérettől függően processTimeWarning=Figyelmeztetés: Ez a folyamat akár egy percig is eltarthat a fájlmérettől függően
pageOrderPrompt=Egyedi oldalsorrend (Adjon meg vesszővel elválasztott oldalszámokat vagy függvényeket, például 2n+1): pageOrderPrompt=Egyedi oldalsorrend (Adjon meg vesszővel elválasztott oldalszámokat vagy függvényeket, például 2n+1):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Ugrás goToPage=Ugrás
true=Igaz true=Igaz
false=Hamis false=Hamis
unknown=Ismeretlen unknown=Ismeretlen
save=Mentés save=Mentés
saveToBrowser=Save to Browser
close=Bezárás close=Bezárás
filesSelected=kiválasztott fájlok filesSelected=kiválasztott fájlok
noFavourites=Nincs hozzáadva kedvenc noFavourites=Nincs hozzáadva kedvenc
downloadComplete=Download Complete
bored=Unatkozol? bored=Unatkozol?
alphabet=Ábécé alphabet=Ábécé
downloadPdf=PDF letöltése downloadPdf=PDF letöltése
@@ -51,12 +54,15 @@ notAuthenticatedMessage=Felhasználó nincs hitelesítve.
userNotFoundMessage=A felhasználó nem található. userNotFoundMessage=A felhasználó nem található.
incorrectPasswordMessage=A jelenlegi jelszó helytelen. incorrectPasswordMessage=A jelenlegi jelszó helytelen.
usernameExistsMessage=Az új felhasználónév már létezik. usernameExistsMessage=Az új felhasználónév már létezik.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=Fiókbeállítások
changeCreds.title=Hitelesítés megváltoztatása changeCreds.title=Hitelesítés megváltoztatása
changeCreds.header=Frissítse fiókadatait changeCreds.header=Frissítse fiókadatait
changeCreds.changeUserAndPassword=Alapértelmezett bejelentkezési adatokat használ. Adjon meg egy új jelszót (és felhasználónevet, ha szeretné) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Új felhasználónév changeCreds.newUsername=Új felhasználónév
changeCreds.oldPassword=Jelenlegi jelszó changeCreds.oldPassword=Jelenlegi jelszó
changeCreds.newPassword=Új jelszó changeCreds.newPassword=Új jelszó
@@ -141,12 +147,15 @@ adminUserSettings.header=Adminisztrátori Felhasználói Vezérlési Beállítá
adminUserSettings.admin=Adminisztrátor adminUserSettings.admin=Adminisztrátor
adminUserSettings.user=Felhasználó adminUserSettings.user=Felhasználó
adminUserSettings.addUser=Új felhasználó hozzáadása adminUserSettings.addUser=Új felhasználó hozzáadása
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Szerepek adminUserSettings.roles=Szerepek
adminUserSettings.role=Szerep adminUserSettings.role=Szerep
adminUserSettings.actions=Műveletek adminUserSettings.actions=Műveletek
adminUserSettings.apiUser=Korlátozott API-felhasználó adminUserSettings.apiUser=Korlátozott API-felhasználó
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Csak webes felhasználó adminUserSettings.webOnlyUser=Csak webes felhasználó
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Kényszerítse a felhasználót a felhasználónév/jelszó megváltoztatására bejelentkezéskor adminUserSettings.forceChange=Kényszerítse a felhasználót a felhasználónév/jelszó megváltoztatására bejelentkezéskor
adminUserSettings.submit=Felhasználó mentése adminUserSettings.submit=Felhasználó mentése
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Bejelentkezés login.title=Bejelentkezés
login.header=Bejelentkezés
login.signin=Bejelentkezés login.signin=Bejelentkezés
login.rememberme=Emlékezz rám login.rememberme=Emlékezz rám
login.invalid=Érvénytelen felhasználónév vagy jelszó! login.invalid=Érvénytelen felhasználónév vagy jelszó!
@@ -622,6 +641,18 @@ compare.document.1=Dokumentum 1
compare.document.2=Dokumentum 2 compare.document.2=Dokumentum 2
compare.submit=Összehasonlítás compare.submit=Összehasonlítás
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Aláírás sign.title=Aláírás
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Válassza ki az oldalt a táblázat kinyeréséhez
PDFToCSV.submit=Kinyerés PDFToCSV.submit=Kinyerés
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=PDF felosztása méret vagy oldalszám alapján
split-by-size-or-count.header=PDF felosztása méret vagy oldalszám alapján split-by-size-or-count.header=PDF felosztása méret vagy oldalszám alapján
split-by-size-or-count.type.label=Válassza ki a felosztás típusát split-by-size-or-count.type.label=Válassza ki a felosztás típusát
split-by-size-or-count.type.size=Méret alapján split-by-size-or-count.type.size=Méret alapján
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vízszintes szakaszok
split-by-sections.horizontal.placeholder=Adja meg a vízszintes szakaszok számát split-by-sections.horizontal.placeholder=Adja meg a vízszintes szakaszok számát
split-by-sections.vertical.placeholder=Adja meg a függőleges szakaszok számát split-by-sections.vertical.placeholder=Adja meg a függőleges szakaszok számát
split-by-sections.submit=Felosztás split-by-sections.submit=Felosztás
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl=right to left) # the direction that the language is written (ltr=left to right, rtl=right to left)
@@ -11,14 +11,17 @@ imgPrompt=Pilih Gambar
genericSubmit=Kirim genericSubmit=Kirim
processTimeWarning=Peringatan: Proses ini dapat memakan waktu hingga satu menit, tergantung pada ukuran berkas processTimeWarning=Peringatan: Proses ini dapat memakan waktu hingga satu menit, tergantung pada ukuran berkas
pageOrderPrompt=Urutan Halaman Khusus (Masukkan daftar nomor halaman yang dipisahkan dengan koma atau Fungsi seperti 2n + 1) : pageOrderPrompt=Urutan Halaman Khusus (Masukkan daftar nomor halaman yang dipisahkan dengan koma atau Fungsi seperti 2n + 1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Ke goToPage=Ke
true=Benar true=Benar
false=Salah false=Salah
unknown=Tidak diketahui unknown=Tidak diketahui
save=Simpan save=Simpan
saveToBrowser=Save to Browser
close=Tutup close=Tutup
filesSelected=berkas dipilih filesSelected=berkas dipilih
noFavourites=Tidak ada favorit yang ditambahkan noFavourites=Tidak ada favorit yang ditambahkan
downloadComplete=Download Complete
bored=Bosan Menunggu? bored=Bosan Menunggu?
alphabet=Abjad alphabet=Abjad
downloadPdf=Unduh PDF downloadPdf=Unduh PDF
@@ -51,12 +54,15 @@ notAuthenticatedMessage=Pengguna tidak ter-autentikasi.
userNotFoundMessage=Pengguna tidak ditemukan. userNotFoundMessage=Pengguna tidak ditemukan.
incorrectPasswordMessage=Kata sandi saat ini salah. incorrectPasswordMessage=Kata sandi saat ini salah.
usernameExistsMessage=Nama pengguna baru sudah ada. usernameExistsMessage=Nama pengguna baru sudah ada.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=Pengaturan Akun
changeCreds.title=Ubah Kredensial changeCreds.title=Ubah Kredensial
changeCreds.header=Perbarui Detail Akun Anda changeCreds.header=Perbarui Detail Akun Anda
changeCreds.changeUserAndPassword=Anda menggunakan kredensial masuk default. Masukkan kata sandi baru (dan nama pengguna jika diinginkan) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=Nama Pengguna Baru changeCreds.newUsername=Nama Pengguna Baru
changeCreds.oldPassword=Kata Sandi Saat Ini changeCreds.oldPassword=Kata Sandi Saat Ini
changeCreds.newPassword=Kata Sandi Baru changeCreds.newPassword=Kata Sandi Baru
@@ -141,12 +147,15 @@ adminUserSettings.header=Pengaturan Kontrol Admin
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Pengguna adminUserSettings.user=Pengguna
adminUserSettings.addUser=Tambahkan Pengguna Baru adminUserSettings.addUser=Tambahkan Pengguna Baru
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Peran adminUserSettings.roles=Peran
adminUserSettings.role=Peran adminUserSettings.role=Peran
adminUserSettings.actions=Tindakan adminUserSettings.actions=Tindakan
adminUserSettings.apiUser=Pengguna API Terbatas adminUserSettings.apiUser=Pengguna API Terbatas
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Pengguna Khusus Web adminUserSettings.webOnlyUser=Pengguna Khusus Web
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Memaksa pengguna untuk mengubah nama pengguna/kata sandi saat masuk adminUserSettings.forceChange=Memaksa pengguna untuk mengubah nama pengguna/kata sandi saat masuk
adminUserSettings.submit=Simpan Pengguna adminUserSettings.submit=Simpan Pengguna
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=Masuk login.title=Masuk
login.header=Masuk
login.signin=Masuk login.signin=Masuk
login.rememberme=Ingat saya login.rememberme=Ingat saya
login.invalid=Nama pengguna atau kata sandi tidak valid. login.invalid=Nama pengguna atau kata sandi tidak valid.
@@ -622,6 +641,18 @@ compare.document.1=Dokumen 1
compare.document.2=Dokumen 2 compare.document.2=Dokumen 2
compare.submit=Bandingkan compare.submit=Bandingkan
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=Tanda sign.title=Tanda
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Pilih halaman untuk mengambil tabel
PDFToCSV.submit=Ektraksi PDFToCSV.submit=Ektraksi
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Pisahkan PDF berdasarkan ukuran atau jumlah
split-by-size-or-count.header=Pisahkan PDF berdasarkan ukuran atau jumlah split-by-size-or-count.header=Pisahkan PDF berdasarkan ukuran atau jumlah
split-by-size-or-count.type.label=Pilih Tipe Split split-by-size-or-count.type.label=Pilih Tipe Split
split-by-size-or-count.type.size=Berdasarkan Ukuran split-by-size-or-count.type.size=Berdasarkan Ukuran
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Pembagian Vertikal
split-by-sections.horizontal.placeholder=Input angka untuk pembagian horizontal split-by-sections.horizontal.placeholder=Input angka untuk pembagian horizontal
split-by-sections.vertical.placeholder=Input angka untuk pembagian vertikal split-by-sections.vertical.placeholder=Input angka untuk pembagian vertikal
split-by-sections.submit=Pisahkan PDF split-by-sections.submit=Pisahkan PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=Scegli immagine/i
genericSubmit=Invia genericSubmit=Invia
processTimeWarning=Nota: Questo processo potrebbe richiedere fino a un minuto in base alla dimensione dei file processTimeWarning=Nota: Questo processo potrebbe richiedere fino a un minuto in base alla dimensione dei file
pageOrderPrompt=Ordine delle pagine (inserisci una lista di numeri separati da virgola): pageOrderPrompt=Ordine delle pagine (inserisci una lista di numeri separati da virgola):
pageSelectionPrompt=Selezione pagina personalizzata (inserisci un elenco separato da virgole di numeri di pagina 1,5,6 o funzioni come 2n+1) :
goToPage=Vai goToPage=Vai
true=Vero true=Vero
false=Falso false=Falso
unknown=Sconosciuto unknown=Sconosciuto
save=Salva save=Salva
saveToBrowser=Save to Browser
close=Chiudi close=Chiudi
filesSelected=file selezionati filesSelected=file selezionati
noFavourites=Nessun preferito noFavourites=Nessun preferito
downloadComplete=Download Complete
bored=Stanco di aspettare? bored=Stanco di aspettare?
alphabet=Alfabeto alphabet=Alfabeto
downloadPdf=Scarica PDF downloadPdf=Scarica PDF
@@ -51,12 +54,15 @@ notAuthenticatedMessage=Utente non autenticato.
userNotFoundMessage=Utente non trovato. userNotFoundMessage=Utente non trovato.
incorrectPasswordMessage=La password attuale non è corretta. incorrectPasswordMessage=La password attuale non è corretta.
usernameExistsMessage=Il nuovo nome utente esiste già. usernameExistsMessage=Il nuovo nome utente esiste già.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Impossibile eliminare l'utente attualmente connesso.
deleteUsernameExistsMessage=Il nome utente non esiste e non può essere eliminato.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Caricamento personalizzato pipeline.uploadButton=Caricamento personalizzato
pipeline.configureButton=Configura pipeline.configureButton=Configura
pipeline.defaultOption=Personalizzato pipeline.defaultOption=Personalizzato
@@ -106,7 +112,7 @@ settings.accountSettings=Impostazioni Account
changeCreds.title=Cambia credenziali changeCreds.title=Cambia credenziali
changeCreds.header=Aggiorna i dettagli del tuo account changeCreds.header=Aggiorna i dettagli del tuo account
changeCreds.changeUserAndPassword=Stai utilizzando le credenziali di accesso predefinite. Inserisci una nuova password (e un nome utente se lo desideri) changeCreds.changePassword=Stai utilizzando le credenziali di accesso predefinite. Inserisci una nuova password
changeCreds.newUsername=Nuovo nome utente changeCreds.newUsername=Nuovo nome utente
changeCreds.oldPassword=Password attuale changeCreds.oldPassword=Password attuale
changeCreds.newPassword=Nuova Password changeCreds.newPassword=Nuova Password
@@ -141,12 +147,15 @@ adminUserSettings.header=Impostazioni di controllo utente amministratore
adminUserSettings.admin=Amministratore adminUserSettings.admin=Amministratore
adminUserSettings.user=Utente adminUserSettings.user=Utente
adminUserSettings.addUser=Aggiungi un nuovo Utente adminUserSettings.addUser=Aggiungi un nuovo Utente
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=Ruoli adminUserSettings.roles=Ruoli
adminUserSettings.role=Ruolo adminUserSettings.role=Ruolo
adminUserSettings.actions=Azioni adminUserSettings.actions=Azioni
adminUserSettings.apiUser=Utente API limitato adminUserSettings.apiUser=Utente API limitato
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=Utente solo Web adminUserSettings.webOnlyUser=Utente solo Web
adminUserSettings.demoUser=Utente demo (nessuna impostazione personalizzata) adminUserSettings.demoUser=Utente demo (nessuna impostazione personalizzata)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Forza l'utente a cambiare nome username/password all'accesso adminUserSettings.forceChange=Forza l'utente a cambiare nome username/password all'accesso
adminUserSettings.submit=Salva utente adminUserSettings.submit=Salva utente
@@ -366,7 +375,7 @@ showJS.tags=JS
home.autoRedact.title=Redazione automatica home.autoRedact.title=Redazione automatica
home.autoRedact.desc=Redige automaticamente (oscura) il testo in un PDF in base al testo immesso home.autoRedact.desc=Redige automaticamente (oscura) il testo in un PDF in base al testo immesso
autoRedact.tags=Redact,Hide,black out,black,marker,hidden autoRedact.tags=Redigere,nascondere,oscurare,nero,pennarello,nascosto
home.tableExtraxt.title=Da PDF a CSV home.tableExtraxt.title=Da PDF a CSV
home.tableExtraxt.desc=Estrae tabelle da un PDF convertendolo in CSV home.tableExtraxt.desc=Estrae tabelle da un PDF convertendolo in CSV
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Aggiungi testo o aggiungi timbri immagine nelle posizi
AddStampRequest.tags=Timbro, Aggiungi immagine, Centra immagine, Filigrana, PDF, Incorpora, Personalizza AddStampRequest.tags=Timbro, Aggiungi immagine, Centra immagine, Filigrana, PDF, Incorpora, Personalizza
home.PDFToBook.title=PDF in libro
home.PDFToBook.desc=Converte PDF in formati libro/fumetto utilizzando Calibre
PDFToBook.tags=Libro,fumetto,calibre,conversione,manga,amazon,kindle
home.BookToPDF.title=Libro in PDF
home.BookToPDF.desc=Converte i formati di libri/fumetti in PDF utilizzando Calibre
BookToPDF.tags=Libro,fumetto,calibre,conversione,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Timbro, Aggiungi immagine, Centra immagine, Filigrana, PDF,
########################### ###########################
#login #login
login.title=Accedi login.title=Accedi
login.header=Accedi
login.signin=Accedi login.signin=Accedi
login.rememberme=Ricordami login.rememberme=Ricordami
login.invalid=Nome utente o password errati. login.invalid=Nome utente o password errati.
@@ -622,6 +641,18 @@ compare.document.1=Documento 1
compare.document.2=Documento 2 compare.document.2=Documento 2
compare.submit=Compara compare.submit=Compara
#BookToPDF
BookToPDF.title=Libri e fumetti in PDF
BookToPDF.header=Libro in PDF
BookToPDF.credit=Utilizza Calibre
BookToPDF.submit=Converti
#PDFToBook
PDFToBook.title=PDF in libro
PDFToBook.header=PDF in libro
PDFToBook.selectText.1=Formato
PDFToBook.credit=Utilizzo Calibre
PDFToBook.submit=Converti
#sign #sign
sign.title=Firma sign.title=Firma
@@ -867,7 +898,7 @@ changeMetadata.keywords=Parole chiave:
changeMetadata.modDate=Data di modifica (yyyy/MM/dd HH:mm:ss): changeMetadata.modDate=Data di modifica (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=Produttore: changeMetadata.producer=Produttore:
changeMetadata.subject=Oggetto: changeMetadata.subject=Oggetto:
changeMetadata.trapped=Trapped: changeMetadata.trapped=Recuperato:
changeMetadata.selectText.4=Altre proprietà: changeMetadata.selectText.4=Altre proprietà:
changeMetadata.selectText.5=Aggiungi proprietà personalizzata: changeMetadata.selectText.5=Aggiungi proprietà personalizzata:
changeMetadata.submit=Cambia Proprietà changeMetadata.submit=Cambia Proprietà
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Scegli la pagina per estrarre la tabella
PDFToCSV.submit=Estrai PDFToCSV.submit=Estrai
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Dividi il PDF per dimensione o numero
split-by-size-or-count.header=Dividi il PDF per dimensione o numero split-by-size-or-count.header=Dividi il PDF per dimensione o numero
split-by-size-or-count.type.label=Seleziona il tipo di divisione split-by-size-or-count.type.label=Seleziona il tipo di divisione
split-by-size-or-count.type.size=Per dimensione split-by-size-or-count.type.size=Per dimensione
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Divisioni verticali
split-by-sections.horizontal.placeholder=Inserire il numero di divisioni orizzontali split-by-sections.horizontal.placeholder=Inserire il numero di divisioni orizzontali
split-by-sections.vertical.placeholder=Inserire il numero di divisioni verticali split-by-sections.vertical.placeholder=Inserire il numero di divisioni verticali
split-by-sections.submit=Dividi PDF split-by-sections.submit=Dividi PDF
split-by-sections.merge=Unisci in un unico PDF
#licenses #licenses
licenses.nav=Licenze licenses.nav=Licenze

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=画像を選択
genericSubmit=送信 genericSubmit=送信
processTimeWarning=警告:この処理はファイルサイズによって1分程度かかることがあります processTimeWarning=警告:この処理はファイルサイズによって1分程度かかることがあります
pageOrderPrompt=ページ順序 (ページ番号をカンマ区切り又は2n+1のような関数で入力): pageOrderPrompt=ページ順序 (ページ番号をカンマ区切り又は2n+1のような関数で入力):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=移動 goToPage=移動
true=True true=True
false=False false=False
unknown=不明 unknown=不明
save=保存 save=保存
saveToBrowser=Save to Browser
close=閉じる close=閉じる
filesSelected=選択されたファイル filesSelected=選択されたファイル
noFavourites=お気に入りはありません noFavourites=お気に入りはありません
downloadComplete=Download Complete
bored=待ち時間が退屈 bored=待ち時間が退屈
alphabet=\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8 alphabet=\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8
downloadPdf=PDFをダウンロード downloadPdf=PDFをダウンロード
@@ -51,6 +54,9 @@ notAuthenticatedMessage=ユーザーが認証されていません。
userNotFoundMessage=ユーザーが見つかりません。 userNotFoundMessage=ユーザーが見つかりません。
incorrectPasswordMessage=現在のパスワードが正しくありません。 incorrectPasswordMessage=現在のパスワードが正しくありません。
usernameExistsMessage=新しいユーザー名はすでに存在します。 usernameExistsMessage=新しいユーザー名はすでに存在します。
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
@@ -106,7 +112,7 @@ settings.accountSettings=アカウント設定
changeCreds.title=資格情報の変更 changeCreds.title=資格情報の変更
changeCreds.header=アカウントの詳細を更新する changeCreds.header=アカウントの詳細を更新する
changeCreds.changeUserAndPassword=デフォルトのログイン認証情報を使用しています。新しいパスワード (必要に応じてユーザー名も) を入力してください changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=新しいユーザー名 changeCreds.newUsername=新しいユーザー名
changeCreds.oldPassword=現在のパスワード changeCreds.oldPassword=現在のパスワード
changeCreds.newPassword=新しいパスワード changeCreds.newPassword=新しいパスワード
@@ -141,12 +147,15 @@ adminUserSettings.header=管理者ユーザー制御設定
adminUserSettings.admin=管理者 adminUserSettings.admin=管理者
adminUserSettings.user=ユーザー adminUserSettings.user=ユーザー
adminUserSettings.addUser=新しいユーザを追加 adminUserSettings.addUser=新しいユーザを追加
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=役割 adminUserSettings.roles=役割
adminUserSettings.role=役割 adminUserSettings.role=役割
adminUserSettings.actions=アクション adminUserSettings.actions=アクション
adminUserSettings.apiUser=限定されたAPIユーザー adminUserSettings.apiUser=限定されたAPIユーザー
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=ウェブ専用ユーザー adminUserSettings.webOnlyUser=ウェブ専用ユーザー
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=ログイン時にユーザー名/パスワードを強制的に変更する adminUserSettings.forceChange=ログイン時にユーザー名/パスワードを強制的に変更する
adminUserSettings.submit=ユーザーの保存 adminUserSettings.submit=ユーザーの保存
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=サインイン login.title=サインイン
login.header=サインイン
login.signin=サインイン login.signin=サインイン
login.rememberme=サインイン状態を記憶する login.rememberme=サインイン状態を記憶する
login.invalid=ユーザー名かパスワードが無効です。 login.invalid=ユーザー名かパスワードが無効です。
@@ -622,6 +641,18 @@ compare.document.1=ドキュメント 1
compare.document.2=ドキュメント 2 compare.document.2=ドキュメント 2
compare.submit=比較 compare.submit=比較
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=署名 sign.title=署名
@@ -924,6 +955,7 @@ PDFToCSV.prompt=表を抽出するページを選択
PDFToCSV.submit=変換 PDFToCSV.submit=変換
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=サイズまたは数で分割
split-by-size-or-count.header=サイズまたは数で分割 split-by-size-or-count.header=サイズまたは数で分割
split-by-size-or-count.type.label=分割タイプの選択 split-by-size-or-count.type.label=分割タイプの選択
split-by-size-or-count.type.size=サイズ split-by-size-or-count.type.size=サイズ
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=垂直方向
split-by-sections.horizontal.placeholder=水平方向の分割数を選択 split-by-sections.horizontal.placeholder=水平方向の分割数を選択
split-by-sections.vertical.placeholder=垂直方向の分割数を選択 split-by-sections.vertical.placeholder=垂直方向の分割数を選択
split-by-sections.submit=分割 split-by-sections.submit=分割
split-by-sections.merge=1 つの PDF に結合するかどうか
#licenses #licenses
licenses.nav=ライセンス licenses.nav=ライセンス
@@ -968,3 +1000,4 @@ licenses.module=モジュール
licenses.version=バージョン licenses.version=バージョン
licenses.license=ライセンス licenses.license=ライセンス

View File

@@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,14 +11,17 @@ imgPrompt=이미지 선택
genericSubmit=확인 genericSubmit=확인
processTimeWarning=경고: 파일 크기에 따라 1분 정도 소요될 수 있습니다 processTimeWarning=경고: 파일 크기에 따라 1분 정도 소요될 수 있습니다
pageOrderPrompt=페이지 순서(쉼표로 구분된 페이지 번호 목록 입력): pageOrderPrompt=페이지 순서(쉼표로 구분된 페이지 번호 목록 입력):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=이동 goToPage=이동
true= true=
false=거짓 false=거짓
unknown=알 수 없음 unknown=알 수 없음
save=저장 save=저장
saveToBrowser=Save to Browser
close=닫기 close=닫기
filesSelected=개 파일 선택됨 filesSelected=개 파일 선택됨
noFavourites=즐겨찾기 없음 noFavourites=즐겨찾기 없음
downloadComplete=Download Complete
bored=기다리는 게 지루하신가요? bored=기다리는 게 지루하신가요?
alphabet=\uC54C\uD30C\uBCB3 alphabet=\uC54C\uD30C\uBCB3
downloadPdf=PDF 다운로드 downloadPdf=PDF 다운로드
@@ -51,12 +54,15 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=사용자를 찾을 수 없습니다. userNotFoundMessage=사용자를 찾을 수 없습니다.
incorrectPasswordMessage=현재 비밀번호가 틀립니다. incorrectPasswordMessage=현재 비밀번호가 틀립니다.
usernameExistsMessage=새 사용자명이 이미 존재합니다. usernameExistsMessage=새 사용자명이 이미 존재합니다.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers.
deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
############### ###############
# Pipeline # # Pipeline #
############### ###############
pipeline.header=Pipeline Menu (Alpha) pipeline.header=Pipeline Menu (Beta)
pipeline.uploadButton=Upload Custom pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure pipeline.configureButton=Configure
pipeline.defaultOption=Custom pipeline.defaultOption=Custom
@@ -106,7 +112,7 @@ settings.accountSettings=계정 설정
changeCreds.title=계정 정보 변경 changeCreds.title=계정 정보 변경
changeCreds.header=계정 정보 업데이트 changeCreds.header=계정 정보 업데이트
changeCreds.changeUserAndPassword=기본 제공된 로그인 정보를 사용하고 있습니다. 새 비밀번호를 입력합니다. (필요하다면 사용자명을 변경할 수 있습니다.) changeCreds.changePassword=You are using default login credentials. Please enter a new password
changeCreds.newUsername=새 사용자명 changeCreds.newUsername=새 사용자명
changeCreds.oldPassword=현재 비밀번호 changeCreds.oldPassword=현재 비밀번호
changeCreds.newPassword=새 비밀번호 changeCreds.newPassword=새 비밀번호
@@ -141,12 +147,15 @@ adminUserSettings.header=사용자 관리
adminUserSettings.admin=관리자 adminUserSettings.admin=관리자
adminUserSettings.user=사용자 adminUserSettings.user=사용자
adminUserSettings.addUser=새 사용자 추가 adminUserSettings.addUser=새 사용자 추가
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters.
adminUserSettings.roles=역할 adminUserSettings.roles=역할
adminUserSettings.role=역할 adminUserSettings.role=역할
adminUserSettings.actions=동작 adminUserSettings.actions=동작
adminUserSettings.apiUser=제한된 API 사용 adminUserSettings.apiUser=제한된 API 사용
adminUserSettings.extraApiUser=Additional Limited API User
adminUserSettings.webOnlyUser=웹 사용만 허용 adminUserSettings.webOnlyUser=웹 사용만 허용
adminUserSettings.demoUser=Demo User (No custom settings) adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=다음 로그인 때 사용자명과 비밀번호를 변경하도록 강제 adminUserSettings.forceChange=다음 로그인 때 사용자명과 비밀번호를 변경하도록 강제
adminUserSettings.submit=사용자 저장 adminUserSettings.submit=사용자 저장
@@ -391,6 +400,15 @@ home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book
home.PDFToBook.desc=Converts PDF to Book/Comic formats using calibre
PDFToBook.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
home.BookToPDF.title=Book to PDF
home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@@ -398,6 +416,7 @@ AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Cust
########################### ###########################
#login #login
login.title=로그인 login.title=로그인
login.header=로그인
login.signin=로그인 login.signin=로그인
login.rememberme=로그인 유지 login.rememberme=로그인 유지
login.invalid=사용자 이름이나 비밀번호가 틀립니다. login.invalid=사용자 이름이나 비밀번호가 틀립니다.
@@ -622,6 +641,18 @@ compare.document.1=문서 1
compare.document.2=문서 2 compare.document.2=문서 2
compare.submit=비교 compare.submit=비교
#BookToPDF
BookToPDF.title=Books and Comics to PDF
BookToPDF.header=Book to PDF
BookToPDF.credit=Uses Calibre
BookToPDF.submit=Convert
#PDFToBook
PDFToBook.title=PDF to Book
PDFToBook.header=PDF to Book
PDFToBook.selectText.1=Format
PDFToBook.credit=Uses Calibre
PDFToBook.submit=Convert
#sign #sign
sign.title=서명 sign.title=서명
@@ -924,6 +955,7 @@ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=?? PDFToCSV.submit=??
#split-by-size-or-count #split-by-size-or-count
split-by-size-or-count.title=Split PDF by Size or Count
split-by-size-or-count.header=Split PDF by Size or Count split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size split-by-size-or-count.type.size=By Size
@@ -958,7 +990,7 @@ split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF split-by-sections.submit=Split PDF
split-by-sections.merge=Merge Into One PDF
#licenses #licenses
licenses.nav=Licenses licenses.nav=Licenses

Some files were not shown because too many files have changed in this diff Show More