Compare commits

..

13 Commits

Author SHA1 Message Date
pixeebot[bot]
5dc0a25b26 Sanitized user-provided file names in HTTP multipart uploads 2024-11-26 20:44:19 +00:00
pixeebot[bot]
128cdc90c0 Protect readLine() against DoS 2024-11-26 20:44:18 +00:00
pixeebot[bot]
5a67b0cfe7 Hardening suggestions for Stirling-PDF / ghostscript (#2339)
* Protect `readLine()` against DoS

* Sanitized user-provided file names in HTTP multipart uploads

---------

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
2024-11-26 20:44:07 +00:00
Anthony Stirling
d1acda6440 release bump 2024-11-26 20:38:23 +00:00
Anthony Stirling
5cf3798540 docs 2024-11-26 20:31:31 +00:00
Anthony Stirling
b27044016e more 2024-11-26 20:30:35 +00:00
Anthony Stirling
4aec0bd679 more 2024-11-26 20:27:03 +00:00
Anthony Stirling
ab7610f72c update docs 2024-11-26 20:24:46 +00:00
Anthony Stirling
748392cd29 formatting 2024-11-26 20:18:55 +00:00
Anthony Stirling
f0810f3952 cleanups 2024-11-26 20:15:13 +00:00
Anthony Stirling
298870ed7d Merge remote-tracking branch 'origin/main' into ghostscript 2024-11-26 19:49:20 +00:00
Anthony Stirling
6ec2c34c2b release notes and ghostscript removal 2024-11-26 19:48:42 +00:00
Anthony Stirling
73e64e5898 navbar fix multi tool and compress location 2024-11-25 21:33:23 +00:00
112 changed files with 1064 additions and 32927 deletions

View File

@@ -1,67 +0,0 @@
name: Create Application Bundles
on:
push:
branches:
- 'mac'
workflow_dispatch:
jobs:
create-unix-bundle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew bootJar
- name: Create tar.gz Bundle
run: |
mkdir -p Stirling-PDF-unix
cp build/libs/Stirling-PDF-*.jar Stirling-PDF-unix/Stirling-PDF.jar
cp scripts/launcher.sh Stirling-PDF-unix/Stirling-PDF
cp src/main/resources/static/favicon.ico Stirling-PDF-unix/icon.png
chmod +x Stirling-PDF-unix/Stirling-PDF
tar -czf Stirling-PDF-unix.tar.gz Stirling-PDF-unix/
- name: Upload Unix Bundle
uses: actions/upload-artifact@v4
with:
name: unix-bundle
path: Stirling-PDF-unix.tar.gz
create-mac-bundle:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew bootJar
- name: Create Mac App Bundle
run: |
cp build/libs/Stirling-PDF-*.jar build/libs/Stirling-PDF.jar
chmod +x scripts/create-mac-launcher.sh
./scripts/create-mac-launcher.sh
- name: Create DMG
run: |
hdiutil create -volname "Stirling-PDF" -srcfolder "Stirling-PDF.app" -ov -format UDZO "Stirling-PDF-mac.dmg"
- name: Upload Mac Bundle
uses: actions/upload-artifact@v4
with:
name: mac-bundle
path: Stirling-PDF-mac.dmg

View File

@@ -187,48 +187,47 @@ Certain functionality like `Sign` supports pre-saved files stored at `/customFil
## Supported Languages ## Supported Languages
Stirling-PDF currently supports 38 languages! Stirling-PDF currently supports 37 languages!
| Language | Progress | | Language | Progress |
| -------------------------------------------- | -------------------------------------- | | -------------------------------------------- | -------------------------------------- |
| Arabic (العربية) (ar_AR) | ![95%](https://geps.dev/progress/95) | | Arabic (العربية) (ar_AR) | ![99%](https://geps.dev/progress/99) |
| Azerbaijani (Azərbaycan Dili) (az_AZ) | ![93%](https://geps.dev/progress/93) | | Azerbaijani (Azərbaycan Dili) (az_AZ) | ![76%](https://geps.dev/progress/76) |
| Basque (Euskara) (eu_ES) | ![54%](https://geps.dev/progress/54) | | Basque (Euskara) (eu_ES) | ![54%](https://geps.dev/progress/54) |
| Bulgarian (Български) (bg_BG) | ![90%](https://geps.dev/progress/90) | | Bulgarian (Български) (bg_BG) | ![95%](https://geps.dev/progress/95) |
| Catalan (Català) (ca_CA) | ![85%](https://geps.dev/progress/85) | | Catalan (Català) (ca_CA) | ![89%](https://geps.dev/progress/89) |
| Croatian (Hrvatski) (hr_HR) | ![92%](https://geps.dev/progress/92) | | Croatian (Hrvatski) (hr_HR) | ![96%](https://geps.dev/progress/96) |
| Czech (Česky) (cs_CZ) | ![91%](https://geps.dev/progress/91) | | Czech (Česky) (cs_CZ) | ![96%](https://geps.dev/progress/96) |
| Danish (Dansk) (da_DK) | ![90%](https://geps.dev/progress/90) | | Danish (Dansk) (da_DK) | ![95%](https://geps.dev/progress/95) |
| Dutch (Nederlands) (nl_NL) | ![90%](https://geps.dev/progress/90) | | Dutch (Nederlands) (nl_NL) | ![94%](https://geps.dev/progress/94) |
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) | | English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) | | English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| French (Français) (fr_FR) | ![93%](https://geps.dev/progress/93) | | French (Français) (fr_FR) | ![98%](https://geps.dev/progress/98) |
| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) | | German (Deutsch) (de_DE) | ![98%](https://geps.dev/progress/98) |
| Greek (Ελληνικά) (el_GR) | ![91%](https://geps.dev/progress/91) | | Greek (Ελληνικά) (el_GR) | ![96%](https://geps.dev/progress/96) |
| Hindi (हिंदी) (hi_IN) | ![89%](https://geps.dev/progress/89) | | Hindi (हिंदी) (hi_IN) | ![93%](https://geps.dev/progress/93) |
| Hungarian (Magyar) (hu_HU) | ![92%](https://geps.dev/progress/92) | | Hungarian (Magyar) (hu_HU) | ![96%](https://geps.dev/progress/96) |
| Indonesian (Bahasa Indonesia) (id_ID) | ![91%](https://geps.dev/progress/91) | | Indonesian (Bahasa Indonesia) (id_ID) | ![96%](https://geps.dev/progress/96) |
| Irish (Gaeilge) (ga_IE) | ![83%](https://geps.dev/progress/83) | | Irish (Gaeilge) (ga_IE) | ![86%](https://geps.dev/progress/86) |
| Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) | | Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
| Japanese (日本語) (ja_JP) | ![81%](https://geps.dev/progress/81) | | Japanese (日本語) (ja_JP) | ![84%](https://geps.dev/progress/84) |
| Korean (한국어) (ko_KR) | ![90%](https://geps.dev/progress/90) | | Korean (한국어) (ko_KR) | ![94%](https://geps.dev/progress/94) |
| Norwegian (Norsk) (no_NB) | ![83%](https://geps.dev/progress/83) | | Norwegian (Norsk) (no_NB) | ![86%](https://geps.dev/progress/86) |
| Persian (فارسی) (fa_IR) | ![100%](https://geps.dev/progress/100) | | Polish (Polski) (pl_PL) | ![95%](https://geps.dev/progress/95) |
| Polish (Polski) (pl_PL) | ![91%](https://geps.dev/progress/91) | | Portuguese (Português) (pt_PT) | ![96%](https://geps.dev/progress/96) |
| Portuguese (Português) (pt_PT) | ![91%](https://geps.dev/progress/91) | | Portuguese Brazilian (Português) (pt_BR) | ![96%](https://geps.dev/progress/96) |
| Portuguese Brazilian (Português) (pt_BR) | ![92%](https://geps.dev/progress/92) | | Romanian (Română) (ro_RO) | ![89%](https://geps.dev/progress/89) |
| Romanian (Română) (ro_RO) | ![85%](https://geps.dev/progress/85) | | Russian (Русский) (ru_RU) | ![95%](https://geps.dev/progress/95) |
| Russian (Русский) (ru_RU) | ![91%](https://geps.dev/progress/91) | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![69%](https://geps.dev/progress/69) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![67%](https://geps.dev/progress/67) | | Simplified Chinese (简体中文) (zh_CN) | ![90%](https://geps.dev/progress/90) |
| Simplified Chinese (简体中文) (zh_CN) | ![86%](https://geps.dev/progress/86) | | Slovakian (Slovensky) (sk_SK) | ![81%](https://geps.dev/progress/81) |
| Slovakian (Slovensky) (sk_SK) | ![78%](https://geps.dev/progress/78) | | Spanish (Español) (es_ES) | ![96%](https://geps.dev/progress/96) |
| Spanish (Español) (es_ES) | ![92%](https://geps.dev/progress/92) | | Swedish (Svenska) (sv_SE) | ![95%](https://geps.dev/progress/95) |
| Swedish (Svenska) (sv_SE) | ![91%](https://geps.dev/progress/91) | | Thai (ไทย) (th_TH) | ![94%](https://geps.dev/progress/94) |
| Thai (ไทย) (th_TH) | ![91%](https://geps.dev/progress/91) | | Traditional Chinese (繁體中文) (zh_TW) | ![97%](https://geps.dev/progress/97) |
| Traditional Chinese (繁體中文) (zh_TW) | ![92%](https://geps.dev/progress/92) | | Turkish (Türkçe) (tr_TR) | ![90%](https://geps.dev/progress/90) |
| Turkish (Türkçe) (tr_TR) | ![87%](https://geps.dev/progress/87) | | Ukrainian (Українська) (uk_UA) | ![79%](https://geps.dev/progress/79) |
| Ukrainian (Українська) (uk_UA) | ![76%](https://geps.dev/progress/76) | | Vietnamese (Tiếng Việt) (vi_VN) | ![87%](https://geps.dev/progress/87) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![84%](https://geps.dev/progress/84) |
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.) ## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)

View File

@@ -21,12 +21,10 @@ ext {
imageioVersion = "3.12.0" imageioVersion = "3.12.0"
lombokVersion = "1.18.36" lombokVersion = "1.18.36"
bouncycastleVersion = "1.79" bouncycastleVersion = "1.79"
springSecuritySamlVersion = "6.4.1"
openSamlVersion = "4.3.2"
} }
group = "stirling.software" group = "stirling.software"
version = "0.36.0" version = "0.35.0"
java { java {
@@ -146,18 +144,17 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
implementation "org.springframework.session:spring-session-core:$springBootVersion" implementation 'org.springframework.security:spring-security-saml2-service-provider:6.4.1'
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5' implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
// Don't upgrade h2database // Don't upgrade h2database
runtimeOnly "com.h2database:h2:2.3.232" runtimeOnly "com.h2database:h2:2.3.232"
constraints { constraints {
implementation "org.opensaml:opensaml-core:$openSamlVersion" implementation "org.opensaml:opensaml-core"
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion" implementation "org.opensaml:opensaml-saml-api"
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion" implementation "org.opensaml:opensaml-saml-impl"
} }
implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion" implementation "org.springframework.security:spring-security-saml2-service-provider"
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
implementation 'com.coveo:saml-client:5.0.0' implementation 'com.coveo:saml-client:5.0.0'
@@ -189,7 +186,7 @@ dependencies {
// Image metadata extractor // Image metadata extractor
implementation "com.drewnoakes:metadata-extractor:2.19.0" implementation "com.drewnoakes:metadata-extractor:2.19.0"
implementation "commons-io:commons-io:2.18.0" implementation "commons-io:commons-io:2.17.0"
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0" implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0"
//general PDF //general PDF

View File

@@ -48,6 +48,24 @@ Feature: API Validation
And the response status code should be 200 And the response status code should be 200
@ocr @negative
Scenario: Process PDF with text and OCR with type normal
Given I generate a PDF file as "fileInput"
And the pdf contains 3 pages with random text
And the request data includes
| parameter | value |
| languages | eng |
| sidecar | false |
| deskew | true |
| clean | true |
| cleanFinal | true |
| ocrType | Normal |
| ocrRenderType | hocr |
| removeImagesAfter| false |
When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
Then the response status code should be 500
@ocr @positive @ocr @positive
Scenario: Process PDF with OCR Scenario: Process PDF with OCR
Given I generate a PDF file as "fileInput" Given I generate a PDF file as "fileInput"
@@ -66,6 +84,26 @@ Feature: API Validation
And the response file should have size greater than 0 And the response file should have size greater than 0
And the response status code should be 200 And the response status code should be 200
@ocr @positive
Scenario: Process PDF with OCR with sidecar
Given I generate a PDF file as "fileInput"
And the request data includes
| parameter | value |
| languages | eng |
| sidecar | true |
| deskew | true |
| clean | true |
| cleanFinal | true |
| ocrType | Force |
| ocrRenderType | hocr |
| removeImagesAfter| false |
When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
Then the response content type should be "application/octet-stream"
And the response file should have extension ".zip"
And the response ZIP should contain 2 files
And the response file should have size greater than 0
And the response status code should be 200
@libre @positive @libre @positive
Scenario Outline: Convert PDF to various word formats Scenario Outline: Convert PDF to various word formats

View File

@@ -1,76 +0,0 @@
#!/bin/bash
# scripts/create-mac-launcher.sh
# Create app structure
APP_NAME="Stirling-PDF"
APP_BUNDLE="$APP_NAME.app"
mkdir -p "$APP_BUNDLE/Contents/"{MacOS,Resources,Java}
# Convert icon
sips -s format icns "src/main/resources/static/favicon.ico" --out "$APP_BUNDLE/Contents/Resources/AppIcon.icns"
# Create Info.plist
cat > "$APP_BUNDLE/Contents/Info.plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>$APP_NAME</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>com.frooodle.stirlingpdf</string>
<key>CFBundleName</key>
<string>$APP_NAME</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.10.0</string>
<key>LSEnvironment</key>
<dict>
<key>BROWSER_OPEN</key>
<string>true</string>
</dict>
</dict>
</plist>
EOF
# Create launcher script
cat > "$APP_BUNDLE/Contents/MacOS/$APP_NAME" << 'EOF'
#!/bin/bash
# Configuration
MIN_JAVA_VERSION="17"
PREFERRED_JAVA_VERSION="21"
JAVA_DOWNLOAD_URL="https://download.oracle.com/java/21/latest/jdk-21_macos-x64_bin.dmg"
# Check Java version
if type -p java > /dev/null; then
_java=java
elif [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
_java="$JAVA_HOME/bin/java"
else
osascript -e 'display dialog "Java not found. Please install Java 21." buttons {"Download Java", "Cancel"} default button "Download Java"' \
&& open "$JAVA_DOWNLOAD_URL"
exit 1
fi
version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | cut -d'.' -f1)
if [[ "$version" -lt "$MIN_JAVA_VERSION" ]]; then
osascript -e 'display dialog "Wrong Java version. Please install Java 21." buttons {"Download Java", "Cancel"} default button "Download Java"' \
&& open "$JAVA_DOWNLOAD_URL"
exit 1
fi
# Run application
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
exec java -jar "$DIR/../Java/Stirling-PDF.jar" "$@"
EOF
chmod +x "$APP_BUNDLE/Contents/MacOS/$APP_NAME"
# Copy JAR file
cp "build/libs/Stirling-PDF.jar" "$APP_BUNDLE/Contents/Java/"

View File

@@ -1,36 +0,0 @@
#!/bin/bash
# scripts/create-unix-launcher.sh
cat > launcher.sh << 'EOF'
#!/bin/bash
# Configuration
APP_NAME="Stirling-PDF"
MIN_JAVA_VERSION="17"
PREFERRED_JAVA_VERSION="21"
JAVA_DOWNLOAD_URL="https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz"
BROWSER_OPEN="true"
# Check Java version
if type -p java > /dev/null; then
_java=java
elif [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
_java="$JAVA_HOME/bin/java"
else
echo "Java not found. Please install Java 21."
xdg-open "$JAVA_DOWNLOAD_URL"
exit 1
fi
version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | cut -d'.' -f1)
if [[ "$version" -lt "$MIN_JAVA_VERSION" ]]; then
echo "Java version $version detected. Please install Java 21."
xdg-open "$JAVA_DOWNLOAD_URL"
exit 1
fi
# Run application
exec java -jar "$(dirname "$0")/Stirling-PDF.jar" "$@"
EOF
chmod +x launcher.sh

View File

@@ -42,19 +42,14 @@ ignore = [
'addPageNumbers.selectText.3', 'addPageNumbers.selectText.3',
'alphabet', 'alphabet',
'certSign.name', 'certSign.name',
'fileChooser.dragAndDrop',
'home.pipeline.title', 'home.pipeline.title',
'language.direction', 'language.direction',
'legal.impressum',
'licenses.version', 'licenses.version',
'pipeline.title', 'pipeline.title',
'pipelineOptions.pipelineHeader', 'pipelineOptions.pipelineHeader',
'pro', 'pro',
'sponsor', 'sponsor',
'text', 'text',
'validateSignature.cert.bits',
'validateSignature.cert.version',
'validateSignature.status',
'watermark.type.1', 'watermark.type.1',
] ]
@@ -66,6 +61,7 @@ ignore = [
[es_ES] [es_ES]
ignore = [ ignore = [
'adminUserSettings.roles', 'adminUserSettings.roles',
'color',
'error', 'error',
'language.direction', 'language.direction',
'no', 'no',

View File

@@ -1,28 +0,0 @@
#!/bin/bash
# Configuration
MIN_JAVA_VERSION="17"
PREFERRED_JAVA_VERSION="21"
JAVA_DOWNLOAD_URL="https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz"
BROWSER_OPEN="true"
# Check Java version
if type -p java > /dev/null; then
_java=java
elif [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
_java="$JAVA_HOME/bin/java"
else
echo "Java not found. Please install Java 21."
xdg-open "$JAVA_DOWNLOAD_URL"
exit 1
fi
version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | cut -d'.' -f1)
if [[ "$version" -lt "$MIN_JAVA_VERSION" ]]; then
echo "Java version $version detected. Please install Java 21."
xdg-open "$JAVA_DOWNLOAD_URL"
exit 1
fi
# Run application
exec java -jar "$(dirname "$0")/Stirling-PDF.jar" "$@"

View File

@@ -3,14 +3,13 @@ package stirling.software.SPDF.EE;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
@Configuration @Configuration
@Order(Ordered.HIGHEST_PRECEDENCE) @Lazy
@Slf4j @Slf4j
public class EEAppConfig { public class EEAppConfig {

View File

@@ -25,10 +25,9 @@ public class LicenseKeyChecker {
KeygenLicenseVerifier licenseService, ApplicationProperties applicationProperties) { KeygenLicenseVerifier licenseService, ApplicationProperties applicationProperties) {
this.licenseService = licenseService; this.licenseService = licenseService;
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.checkLicense();
} }
@Scheduled(initialDelay = 604800000,fixedRate = 604800000) // 7 days in milliseconds @Scheduled(fixedRate = 604800000, initialDelay = 1000) // 7 days in milliseconds
public void checkLicensePeriodically() { public void checkLicensePeriodically() {
checkLicense(); checkLicense();
} }

View File

@@ -43,6 +43,7 @@ public class ExternalAppDepConfig {
put("unoconv", List.of("Unoconv")); put("unoconv", List.of("Unoconv"));
put("qpdf", List.of("qpdf")); put("qpdf", List.of("qpdf"));
put("tesseract", List.of("tesseract")); put("tesseract", List.of("tesseract"));
} }
}; };

View File

@@ -30,7 +30,6 @@ public class InitialSecuritySetup {
initializeAdminUser(); initializeAdminUser();
} else { } else {
databaseBackupHelper.exportDatabase(); databaseBackupHelper.exportDatabase();
userService.migrateOauth2ToSSO();
} }
initializeInternalApiUser(); initializeInternalApiUser();
} }

View File

@@ -3,16 +3,14 @@ package stirling.software.SPDF.config.security;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.*;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 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;
@@ -34,8 +32,7 @@ import org.springframework.security.saml2.provider.service.authentication.OpenSa
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
@@ -44,7 +41,6 @@ import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
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.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
@@ -68,7 +64,6 @@ import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
@EnableWebSecurity @EnableWebSecurity
@EnableMethodSecurity @EnableMethodSecurity
@Slf4j @Slf4j
@DependsOn("runningEE")
public class SecurityConfiguration { public class SecurityConfiguration {
@Autowired private CustomUserDetailsService userDetailsService; @Autowired private CustomUserDetailsService userDetailsService;
@@ -84,10 +79,6 @@ public class SecurityConfiguration {
@Qualifier("loginEnabled") @Qualifier("loginEnabled")
public boolean loginEnabledValue; public boolean loginEnabledValue;
@Autowired
@Qualifier("runningEE")
public boolean runningEE;
@Autowired ApplicationProperties applicationProperties; @Autowired ApplicationProperties applicationProperties;
@Autowired private UserAuthenticationFilter userAuthenticationFilter; @Autowired private UserAuthenticationFilter userAuthenticationFilter;
@@ -99,14 +90,13 @@ public class SecurityConfiguration {
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
if (applicationProperties.getSecurity().getCsrfDisabled()) {
http.csrf(csrf -> csrf.disable());
}
if (loginEnabledValue) { if (loginEnabledValue) {
http.addFilterBefore( http.addFilterBefore(
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
if (!applicationProperties.getSecurity().getCsrfDisabled()) { if (applicationProperties.getSecurity().getCsrfDisabled()) {
http.csrf(csrf -> csrf.disable());
} else {
CookieCsrfTokenRepository cookieRepo = CookieCsrfTokenRepository cookieRepo =
CookieCsrfTokenRepository.withHttpOnlyFalse(); CookieCsrfTokenRepository.withHttpOnlyFalse();
CsrfTokenRequestAttributeHandler requestHandler = CsrfTokenRequestAttributeHandler requestHandler =
@@ -255,22 +245,12 @@ public class SecurityConfiguration {
} }
// Handle SAML // Handle SAML
if (applicationProperties.getSecurity().isSaml2Activ()) { // && runningEE if (applicationProperties.getSecurity().isSaml2Activ()
// Configure the authentication provider && applicationProperties.getSystem().getEnableAlphaFunctionality()) {
OpenSaml4AuthenticationProvider authenticationProvider = http.authenticationProvider(samlAuthenticationProvider());
new OpenSaml4AuthenticationProvider(); http.saml2Login(
authenticationProvider.setResponseAuthenticationConverter( saml2 ->
new CustomSaml2ResponseAuthenticationConverter(userService));
http.authenticationProvider(authenticationProvider)
.saml2Login(
saml2 -> {
try {
saml2.loginPage("/saml2") saml2.loginPage("/saml2")
.relyingPartyRegistrationRepository(
relyingPartyRegistrations())
.authenticationManager(
new ProviderManager(authenticationProvider))
.successHandler( .successHandler(
new CustomSaml2AuthenticationSuccessHandler( new CustomSaml2AuthenticationSuccessHandler(
loginAttemptService, loginAttemptService,
@@ -278,18 +258,14 @@ public class SecurityConfiguration {
userService)) userService))
.failureHandler( .failureHandler(
new CustomSaml2AuthenticationFailureHandler()) new CustomSaml2AuthenticationFailureHandler())
.authenticationRequestResolver( .permitAll())
authenticationRequestResolver( .addFilterBefore(
relyingPartyRegistrations())); userAuthenticationFilter, Saml2WebSsoAuthenticationFilter.class);
} catch (Exception e) {
log.error("Error configuring SAML2 login", e);
throw new RuntimeException(e);
} }
});
}
} else { } else {
if (!applicationProperties.getSecurity().getCsrfDisabled()) { if (applicationProperties.getSecurity().getCsrfDisabled()) {
http.csrf(csrf -> csrf.disable());
} else {
CookieCsrfTokenRepository cookieRepo = CookieCsrfTokenRepository cookieRepo =
CookieCsrfTokenRepository.withHttpOnlyFalse(); CookieCsrfTokenRepository.withHttpOnlyFalse();
CsrfTokenRequestAttributeHandler requestHandler = CsrfTokenRequestAttributeHandler requestHandler =
@@ -306,6 +282,20 @@ public class SecurityConfiguration {
return http.build(); return http.build();
} }
@Bean
@ConditionalOnProperty(
name = "security.saml2.enabled",
havingValue = "true",
matchIfMissing = false)
public AuthenticationProvider samlAuthenticationProvider() {
OpenSaml4AuthenticationProvider authenticationProvider =
new OpenSaml4AuthenticationProvider();
authenticationProvider.setResponseAuthenticationConverter(
new CustomSaml2ResponseAuthenticationConverter(userService));
return authenticationProvider;
}
// Client Registration Repository for OAUTH2 OIDC Login
@Bean @Bean
@ConditionalOnProperty( @ConditionalOnProperty(
value = "security.oauth2.enabled", value = "security.oauth2.enabled",
@@ -442,12 +432,11 @@ public class SecurityConfiguration {
havingValue = "true", havingValue = "true",
matchIfMissing = false) matchIfMissing = false)
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception { public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
SAML2 samlConf = applicationProperties.getSecurity().getSaml2(); SAML2 samlConf = applicationProperties.getSecurity().getSaml2();
X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert());
Saml2X509Credential verificationCredential = Saml2X509Credential.verification(idpCert);
Resource privateKeyResource = samlConf.getPrivateKey(); Resource privateKeyResource = samlConf.getPrivateKey();
Resource certificateResource = samlConf.getSpCert(); Resource certificateResource = samlConf.getSpCert();
Saml2X509Credential signingCredential = Saml2X509Credential signingCredential =
@@ -456,97 +445,26 @@ public class SecurityConfiguration {
CertificateUtils.readCertificate(certificateResource), CertificateUtils.readCertificate(certificateResource),
Saml2X509CredentialType.SIGNING); Saml2X509CredentialType.SIGNING);
X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert());
Saml2X509Credential verificationCredential = Saml2X509Credential.verification(idpCert);
RelyingPartyRegistration rp = RelyingPartyRegistration rp =
RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId()) RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId())
.signingX509Credentials(c -> c.add(signingCredential)) .signingX509Credentials((c) -> c.add(signingCredential))
.assertingPartyMetadata( .assertingPartyMetadata(
metadata -> (details) ->
metadata.entityId(samlConf.getIdpIssuer()) details.entityId(samlConf.getIdpIssuer())
.singleSignOnServiceLocation( .singleSignOnServiceLocation(
samlConf.getIdpSingleLoginUrl()) samlConf.getIdpSingleLoginUrl())
.verificationX509Credentials( .verificationX509Credentials(
c -> c.add(verificationCredential)) (c) -> c.add(verificationCredential))
.singleSignOnServiceBinding(
Saml2MessageBinding.POST)
.wantAuthnRequestsSigned(true)) .wantAuthnRequestsSigned(true))
.build(); .build();
return new InMemoryRelyingPartyRegistrationRepository(rp); return new InMemoryRelyingPartyRegistrationRepository(rp);
} }
@Bean @Bean
@ConditionalOnProperty(
name = "security.saml2.enabled",
havingValue = "true",
matchIfMissing = false)
public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver(
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
OpenSaml4AuthenticationRequestResolver resolver =
new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationRepository);
resolver.setAuthnRequestCustomizer(
customizer -> {
log.debug("Customizing SAML Authentication request");
AuthnRequest authnRequest = customizer.getAuthnRequest();
log.debug("AuthnRequest ID: {}", authnRequest.getID());
if (authnRequest.getID() == null) {
authnRequest.setID("ARQ" + UUID.randomUUID().toString());
}
log.debug("AuthnRequest new ID after set: {}", authnRequest.getID());
log.debug("AuthnRequest IssueInstant: {}", authnRequest.getIssueInstant());
log.debug(
"AuthnRequest Issuer: {}",
authnRequest.getIssuer() != null
? authnRequest.getIssuer().getValue()
: "null");
HttpServletRequest request = customizer.getRequest();
// Log HTTP request details
log.debug("HTTP Request Method: {}", request.getMethod());
log.debug("Request URI: {}", request.getRequestURI());
log.debug("Request URL: {}", request.getRequestURL().toString());
log.debug("Query String: {}", request.getQueryString());
log.debug("Remote Address: {}", request.getRemoteAddr());
// Log headers
Collections.list(request.getHeaderNames())
.forEach(
headerName -> {
log.debug(
"Header - {}: {}",
headerName,
request.getHeader(headerName));
});
// Log SAML specific parameters
log.debug("SAML Request Parameters:");
log.debug("SAMLRequest: {}", request.getParameter("SAMLRequest"));
log.debug("RelayState: {}", request.getParameter("RelayState"));
// Log session debugrmation if exists
if (request.getSession(false) != null) {
log.debug("Session ID: {}", request.getSession().getId());
}
// Log any assertions consumer service details if present
if (authnRequest.getAssertionConsumerServiceURL() != null) {
log.debug(
"AssertionConsumerServiceURL: {}",
authnRequest.getAssertionConsumerServiceURL());
}
// Log NameID policy if present
if (authnRequest.getNameIDPolicy() != null) {
log.debug(
"NameIDPolicy Format: {}",
authnRequest.getNameIDPolicy().getFormat());
}
});
return resolver;
}
public DaoAuthenticationProvider daoAuthenticationProvider() { public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService); provider.setUserDetailsService(userDetailsService);

View File

@@ -18,7 +18,6 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface; import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface;
@@ -51,19 +50,8 @@ public class UserService implements UserServiceInterface {
@Autowired ApplicationProperties applicationProperties; @Autowired ApplicationProperties applicationProperties;
@Transactional
public void migrateOauth2ToSSO() {
userRepository
.findByAuthenticationTypeIgnoreCase("OAUTH2")
.forEach(
user -> {
user.setAuthenticationType(AuthenticationType.SSO);
userRepository.save(user);
});
}
// Handle OAUTH2 login and user auto creation. // Handle OAUTH2 login and user auto creation.
public boolean processSSOPostLogin(String username, boolean autoCreateUser) public boolean processOAuth2PostLogin(String username, boolean autoCreateUser)
throws IllegalArgumentException, IOException { throws IllegalArgumentException, IOException {
if (!isUsernameValid(username)) { if (!isUsernameValid(username)) {
return false; return false;
@@ -73,7 +61,7 @@ public class UserService implements UserServiceInterface {
return true; return true;
} }
if (autoCreateUser) { if (autoCreateUser) {
saveUser(username, AuthenticationType.SSO); saveUser(username, AuthenticationType.OAUTH2);
return true; return true;
} }
return false; return false;

View File

@@ -82,7 +82,8 @@ public class CustomOAuth2AuthenticationSuccessHandler
} }
if (userService.usernameExistsIgnoreCase(username) if (userService.usernameExistsIgnoreCase(username)
&& userService.hasPassword(username) && userService.hasPassword(username)
&& !userService.isAuthenticationTypeByUsername(username, AuthenticationType.SSO) && !userService.isAuthenticationTypeByUsername(
username, AuthenticationType.OAUTH2)
&& oAuth.getAutoCreateUser()) { && oAuth.getAutoCreateUser()) {
response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true"); response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
return; return;
@@ -94,7 +95,7 @@ public class CustomOAuth2AuthenticationSuccessHandler
return; return;
} }
if (principal instanceof OAuth2User) { if (principal instanceof OAuth2User) {
userService.processSSOPostLogin(username, oAuth.getAutoCreateUser()); userService.processOAuth2PostLogin(username, oAuth.getAutoCreateUser());
} }
response.sendRedirect(contextPath + "/"); response.sendRedirect(contextPath + "/");
return; return;

View File

@@ -3,14 +3,12 @@ package stirling.software.SPDF.config.security.saml2;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader; import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@@ -30,26 +28,15 @@ public class CertificateUtils {
} }
public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception { public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception {
try (PEMParser pemParser = try (PemReader pemReader =
new PEMParser( new PemReader(
new InputStreamReader( new InputStreamReader(
privateKeyResource.getInputStream(), StandardCharsets.UTF_8))) { privateKeyResource.getInputStream(), StandardCharsets.UTF_8))) {
PemObject pemObject = pemReader.readPemObject();
Object object = pemParser.readObject(); byte[] decodedKey = pemObject.getContent();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter(); return (RSAPrivateKey)
KeyFactory.getInstance("RSA")
if (object instanceof PEMKeyPair) { .generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
// Handle traditional RSA private key format
PEMKeyPair keypair = (PEMKeyPair) object;
return (RSAPrivateKey) converter.getPrivateKey(keypair.getPrivateKeyInfo());
} else if (object instanceof PrivateKeyInfo) {
// Handle PKCS#8 format
return (RSAPrivateKey) converter.getPrivateKey((PrivateKeyInfo) object);
} else {
throw new IllegalArgumentException(
"Unsupported key format: "
+ (object != null ? object.getClass().getName() : "null"));
}
} }
} }
} }

View File

@@ -12,7 +12,6 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.LoginAttemptService; import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
@@ -21,11 +20,11 @@ import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.utils.RequestUriUtils; import stirling.software.SPDF.utils.RequestUriUtils;
@AllArgsConstructor @AllArgsConstructor
@Slf4j
public class CustomSaml2AuthenticationSuccessHandler public class CustomSaml2AuthenticationSuccessHandler
extends SavedRequestAwareAuthenticationSuccessHandler { extends SavedRequestAwareAuthenticationSuccessHandler {
private LoginAttemptService loginAttemptService; private LoginAttemptService loginAttemptService;
private ApplicationProperties applicationProperties; private ApplicationProperties applicationProperties;
private UserService userService; private UserService userService;
@@ -35,12 +34,10 @@ public class CustomSaml2AuthenticationSuccessHandler
throws ServletException, IOException { throws ServletException, IOException {
Object principal = authentication.getPrincipal(); Object principal = authentication.getPrincipal();
log.debug("Starting SAML2 authentication success handling");
if (principal instanceof CustomSaml2AuthenticatedPrincipal) { if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
String username = ((CustomSaml2AuthenticatedPrincipal) principal).getName(); String username = ((CustomSaml2AuthenticatedPrincipal) principal).getName();
log.debug("Authenticated principal found for user: {}", username); // Get the saved request
HttpSession session = request.getSession(false); HttpSession session = request.getSession(false);
String contextPath = request.getContextPath(); String contextPath = request.getContextPath();
SavedRequest savedRequest = SavedRequest savedRequest =
@@ -48,77 +45,46 @@ public class CustomSaml2AuthenticationSuccessHandler
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST") ? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
: null; : null;
log.debug(
"Session exists: {}, Saved request exists: {}",
session != null,
savedRequest != null);
if (savedRequest != null if (savedRequest != null
&& !RequestUriUtils.isStaticResource( && !RequestUriUtils.isStaticResource(
contextPath, savedRequest.getRedirectUrl())) { contextPath, savedRequest.getRedirectUrl())) {
log.debug( // Redirect to the original destination
"Valid saved request found, redirecting to original destination: {}",
savedRequest.getRedirectUrl());
super.onAuthenticationSuccess(request, response, authentication); super.onAuthenticationSuccess(request, response, authentication);
} else { } else {
SAML2 saml2 = applicationProperties.getSecurity().getSaml2(); SAML2 saml2 = applicationProperties.getSecurity().getSaml2();
log.debug(
"Processing SAML2 authentication with autoCreateUser: {}",
saml2.getAutoCreateUser());
if (loginAttemptService.isBlocked(username)) { if (loginAttemptService.isBlocked(username)) {
log.debug("User {} is blocked due to too many login attempts", username);
if (session != null) { if (session != null) {
session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST"); session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST");
} }
throw new LockedException( throw new LockedException(
"Your account has been locked due to too many failed login attempts."); "Your account has been locked due to too many failed login attempts.");
} }
if (userService.usernameExistsIgnoreCase(username)
boolean userExists = userService.usernameExistsIgnoreCase(username); && userService.hasPassword(username)
boolean hasPassword = userExists && userService.hasPassword(username); && !userService.isAuthenticationTypeByUsername(
boolean isSSOUser = username, AuthenticationType.OAUTH2)
userExists && saml2.getAutoCreateUser()) {
&& userService.isAuthenticationTypeByUsername(
username, AuthenticationType.SSO);
log.debug(
"User status - Exists: {}, Has password: {}, Is SSO user: {}",
userExists,
hasPassword,
isSSOUser);
if (userExists && hasPassword && !isSSOUser && saml2.getAutoCreateUser()) {
log.debug(
"User {} exists with password but is not SSO user, redirecting to logout",
username);
response.sendRedirect( response.sendRedirect(
contextPath + "/logout?oauth2AuthenticationErrorWeb=true"); contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
return; return;
} }
try { try {
if (saml2.getBlockRegistration() && !userExists) { if (saml2.getBlockRegistration()
log.debug("Registration blocked for new user: {}", username); && !userService.usernameExistsIgnoreCase(username)) {
response.sendRedirect( response.sendRedirect(
contextPath + "/login?erroroauth=oauth2_admin_blocked_user"); contextPath + "/login?erroroauth=oauth2_admin_blocked_user");
return; return;
} }
log.debug("Processing SSO post-login for user: {}", username); userService.processOAuth2PostLogin(username, saml2.getAutoCreateUser());
userService.processSSOPostLogin(username, saml2.getAutoCreateUser());
log.debug("Successfully processed authentication for user: {}", username);
response.sendRedirect(contextPath + "/"); response.sendRedirect(contextPath + "/");
return; return;
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
log.debug(
"Invalid username detected for user: {}, redirecting to logout",
username);
response.sendRedirect(contextPath + "/logout?invalidUsername=true"); response.sendRedirect(contextPath + "/logout?invalidUsername=true");
return; return;
} }
} }
} else { } else {
log.debug("Non-SAML2 principal detected, delegating to parent handler");
super.onAuthenticationSuccess(request, response, authentication); super.onAuthenticationSuccess(request, response, authentication);
} }
} }

View File

@@ -3,6 +3,8 @@ package stirling.software.SPDF.config.security.saml2;
import java.util.*; import java.util.*;
import org.opensaml.core.xml.XMLObject; import org.opensaml.core.xml.XMLObject;
import org.opensaml.core.xml.schema.XSBoolean;
import org.opensaml.core.xml.schema.XSString;
import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute; import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.core.AttributeStatement; import org.opensaml.saml.saml2.core.AttributeStatement;
@@ -28,60 +30,15 @@ public class CustomSaml2ResponseAuthenticationConverter
this.userService = userService; this.userService = userService;
} }
private Map<String, List<Object>> extractAttributes(Assertion assertion) {
Map<String, List<Object>> attributes = new HashMap<>();
for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) {
for (Attribute attribute : attributeStatement.getAttributes()) {
String attributeName = attribute.getName();
List<Object> values = new ArrayList<>();
for (XMLObject xmlObject : attribute.getAttributeValues()) {
// Get the text content directly
String value = xmlObject.getDOM().getTextContent();
if (value != null && !value.trim().isEmpty()) {
values.add(value);
}
}
if (!values.isEmpty()) {
// Store with both full URI and last part of the URI
attributes.put(attributeName, values);
String shortName = attributeName.substring(attributeName.lastIndexOf('/') + 1);
attributes.put(shortName, values);
}
}
}
return attributes;
}
@Override @Override
public Saml2Authentication convert(ResponseToken responseToken) { public Saml2Authentication convert(ResponseToken responseToken) {
// Extract the assertion from the response
Assertion assertion = responseToken.getResponse().getAssertions().get(0); Assertion assertion = responseToken.getResponse().getAssertions().get(0);
Map<String, List<Object>> attributes = extractAttributes(assertion);
// Debug log with actual values // Extract the NameID
log.debug("Extracted SAML Attributes: " + attributes); String nameId = assertion.getSubject().getNameID().getValue();
// Try to get username/identifier in order of preference Optional<User> userOpt = userService.findByUsernameIgnoreCase(nameId);
String userIdentifier = null;
if (hasAttribute(attributes, "username")) {
userIdentifier = getFirstAttributeValue(attributes, "username");
} else if (hasAttribute(attributes, "emailaddress")) {
userIdentifier = getFirstAttributeValue(attributes, "emailaddress");
} else if (hasAttribute(attributes, "name")) {
userIdentifier = getFirstAttributeValue(attributes, "name");
} else if (hasAttribute(attributes, "upn")) {
userIdentifier = getFirstAttributeValue(attributes, "upn");
} else if (hasAttribute(attributes, "uid")) {
userIdentifier = getFirstAttributeValue(attributes, "uid");
} else {
userIdentifier = assertion.getSubject().getNameID().getValue();
}
// Rest of your existing code...
Optional<User> userOpt = userService.findByUsernameIgnoreCase(userIdentifier);
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_USER"); SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
if (userOpt.isPresent()) { if (userOpt.isPresent()) {
User user = userOpt.get(); User user = userOpt.get();
@@ -91,27 +48,39 @@ public class CustomSaml2ResponseAuthenticationConverter
} }
} }
// Extract the SessionIndexes
List<String> sessionIndexes = new ArrayList<>(); List<String> sessionIndexes = new ArrayList<>();
for (AuthnStatement authnStatement : assertion.getAuthnStatements()) { for (AuthnStatement authnStatement : assertion.getAuthnStatements()) {
sessionIndexes.add(authnStatement.getSessionIndex()); sessionIndexes.add(authnStatement.getSessionIndex());
} }
CustomSaml2AuthenticatedPrincipal principal = // Extract the Attributes
new CustomSaml2AuthenticatedPrincipal( Map<String, List<Object>> attributes = extractAttributes(assertion);
userIdentifier, attributes, userIdentifier, sessionIndexes);
// Create the custom principal
CustomSaml2AuthenticatedPrincipal principal =
new CustomSaml2AuthenticatedPrincipal(nameId, attributes, nameId, sessionIndexes);
// Create the Saml2Authentication
return new Saml2Authentication( return new Saml2Authentication(
principal, principal,
responseToken.getToken().getSaml2Response(), responseToken.getToken().getSaml2Response(),
Collections.singletonList(simpleGrantedAuthority)); Collections.singletonList(simpleGrantedAuthority));
} }
private boolean hasAttribute(Map<String, List<Object>> attributes, String name) { private Map<String, List<Object>> extractAttributes(Assertion assertion) {
return attributes.containsKey(name) && !attributes.get(name).isEmpty(); Map<String, List<Object>> attributes = new HashMap<>();
for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) {
for (Attribute attribute : attributeStatement.getAttributes()) {
String attributeName = attribute.getName();
List<Object> values = new ArrayList<>();
for (XMLObject xmlObject : attribute.getAttributeValues()) {
log.info("BOOL: " + ((XSBoolean) xmlObject).getValue());
values.add(((XSString) xmlObject).getValue());
} }
attributes.put(attributeName, values);
private String getFirstAttributeValue(Map<String, List<Object>> attributes, String name) { }
List<Object> values = attributes.get(name); }
return values != null && !values.isEmpty() ? values.get(0).toString() : null; return attributes;
} }
} }

View File

@@ -244,8 +244,8 @@ public class UserController {
return new RedirectView("/addUsers?messageType=invalidRole", true); return new RedirectView("/addUsers?messageType=invalidRole", true);
} }
if (authType.equalsIgnoreCase(AuthenticationType.SSO.toString())) { if (authType.equalsIgnoreCase(AuthenticationType.OAUTH2.toString())) {
userService.saveUser(username, AuthenticationType.SSO, role); userService.saveUser(username, AuthenticationType.OAUTH2, role);
} else { } else {
if (password.isBlank()) { if (password.isBlank()) {
return new RedirectView("/addUsers?messageType=invalidPassword", true); return new RedirectView("/addUsers?messageType=invalidPassword", true);

View File

@@ -14,8 +14,6 @@ import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -28,7 +26,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.MetadataRequest; import stirling.software.SPDF.model.api.misc.MetadataRequest;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;
import stirling.software.SPDF.utils.propertyeditor.StringToMapPropertyEditor;
@RestController @RestController
@RequestMapping("/api/v1/misc") @RequestMapping("/api/v1/misc")
@@ -47,11 +44,6 @@ public class MetadataController {
return entry; return entry;
} }
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Map.class, "allRequestParams", new StringToMapPropertyEditor());
}
@PostMapping(consumes = "multipart/form-data", value = "/update-metadata") @PostMapping(consumes = "multipart/form-data", value = "/update-metadata")
@Operation( @Operation(
summary = "Update metadata of a PDF file", summary = "Update metadata of a PDF file",

View File

@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc; package stirling.software.SPDF.controller.api.misc;
import io.github.pixee.security.BoundedLineReader;
import io.github.pixee.security.Filenames;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@@ -33,8 +35,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.BoundedLineReader;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -176,9 +176,7 @@ public class OCRController {
// Read the final PDF file // Read the final PDF file
byte[] pdfContent = Files.readAllBytes(finalOutputFile); byte[] pdfContent = Files.readAllBytes(finalOutputFile);
String outputFilename = String outputFilename =
Filenames.toSimpleFileName(inputFile.getOriginalFilename()) Filenames.toSimpleFileName(inputFile.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + "_OCR.pdf";
.replaceFirst("[.][^.]+$", "")
+ "_OCR.pdf";
return ResponseEntity.ok() return ResponseEntity.ok()
.header( .header(

View File

@@ -50,6 +50,7 @@ public class RepairController {
MultipartFile inputFile = request.getFileInput(); MultipartFile inputFile = request.getFileInput();
// Save the uploaded file to a temporary location // Save the uploaded file to a temporary location
Path tempInputFile = Files.createTempFile("input_", ".pdf"); Path tempInputFile = Files.createTempFile("input_", ".pdf");
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
byte[] pdfBytes = null; byte[] pdfBytes = null;
inputFile.transferTo(tempInputFile.toFile()); inputFile.transferTo(tempInputFile.toFile());
try { try {
@@ -60,13 +61,14 @@ public class RepairController {
command.add("--qdf"); // Linearizes and normalizes PDF structure command.add("--qdf"); // Linearizes and normalizes PDF structure
command.add("--object-streams=disable"); // Can help with some corruptions command.add("--object-streams=disable"); // Can help with some corruptions
command.add(tempInputFile.toString()); command.add(tempInputFile.toString());
command.add(tempOutputFile.toString());
ProcessExecutorResult returnCode = ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF) ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF)
.runCommandWithOutputHandling(command); .runCommandWithOutputHandling(command);
// Read the optimized PDF file // Read the optimized PDF file
pdfBytes = pdfDocumentFactory.loadToBytes(tempInputFile.toFile()); pdfBytes = pdfDocumentFactory.loadToBytes(tempOutputFile.toFile());
// Return the optimized PDF as a response // Return the optimized PDF as a response
String outputFilename = String outputFilename =
@@ -77,6 +79,7 @@ public class RepairController {
} finally { } finally {
// Clean up the temporary files // Clean up the temporary files
Files.deleteIfExists(tempInputFile); Files.deleteIfExists(tempInputFile);
Files.deleteIfExists(tempOutputFile);
} }
} }
} }

View File

@@ -229,22 +229,10 @@ public class StampController {
calculatePositionY( calculatePositionY(
pageSize, position, calculateTextCapHeight(font, fontSize), margin); pageSize, position, calculateTextCapHeight(font, fontSize), margin);
} }
// Split the stampText into multiple lines
String[] lines = stampText.split("\\\\n");
// Calculate dynamic line height based on font ascent and descent
float ascent = font.getFontDescriptor().getAscent();
float descent = font.getFontDescriptor().getDescent();
float lineHeight = ((ascent - descent) / 1000) * fontSize;
contentStream.beginText(); contentStream.beginText();
for (int i = 0; i < lines.length; i++) { contentStream.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(rotation), x, y));
String line = lines[i]; contentStream.showText(stampText);
// Set the text matrix for each line with rotation
contentStream.setTextMatrix(
Matrix.getRotateInstance(Math.toRadians(rotation), x, y - (i * lineHeight)));
contentStream.showText(line);
}
contentStream.endText(); contentStream.endText();
} }

View File

@@ -322,14 +322,27 @@ public class GetInfoOnPDF {
PDEncryption pdfEncryption = pdfBoxDoc.getEncryption(); PDEncryption pdfEncryption = pdfBoxDoc.getEncryption();
encryption.put("EncryptionAlgorithm", pdfEncryption.getFilter()); encryption.put("EncryptionAlgorithm", pdfEncryption.getFilter());
encryption.put("KeyLength", pdfEncryption.getLength()); encryption.put("KeyLength", pdfEncryption.getLength());
AccessPermission ap = pdfBoxDoc.getCurrentAccessPermission();
if (ap != null) {
ObjectNode permissionsNode = objectMapper.createObjectNode();
permissionsNode.put("CanAssembleDocument", ap.canAssembleDocument());
permissionsNode.put("CanExtractContent", ap.canExtractContent());
permissionsNode.put(
"CanExtractForAccessibility", ap.canExtractForAccessibility());
permissionsNode.put("CanFillInForm", ap.canFillInForm());
permissionsNode.put("CanModify", ap.canModify());
permissionsNode.put("CanModifyAnnotations", ap.canModifyAnnotations());
permissionsNode.put("CanPrint", ap.canPrint());
encryption.set(
"Permissions", permissionsNode); // set the node under "Permissions"
}
// Add other encryption-related properties as needed // Add other encryption-related properties as needed
} else { } else {
encryption.put("IsEncrypted", false); encryption.put("IsEncrypted", false);
} }
ObjectNode permissionsNode = objectMapper.createObjectNode();
setNodePermissions(pdfBoxDoc, permissionsNode);
ObjectNode pageInfoParent = objectMapper.createObjectNode(); ObjectNode pageInfoParent = objectMapper.createObjectNode();
for (int pageNum = 0; pageNum < pdfBoxDoc.getNumberOfPages(); pageNum++) { for (int pageNum = 0; pageNum < pdfBoxDoc.getNumberOfPages(); pageNum++) {
ObjectNode pageInfo = objectMapper.createObjectNode(); ObjectNode pageInfo = objectMapper.createObjectNode();
@@ -571,7 +584,6 @@ public class GetInfoOnPDF {
jsonOutput.set("DocumentInfo", docInfoNode); jsonOutput.set("DocumentInfo", docInfoNode);
jsonOutput.set("Compliancy", compliancy); jsonOutput.set("Compliancy", compliancy);
jsonOutput.set("Encryption", encryption); jsonOutput.set("Encryption", encryption);
jsonOutput.set("Permissions", permissionsNode); // set the node under "Permissions"
jsonOutput.set("Other", other); jsonOutput.set("Other", other);
jsonOutput.set("PerPageInfo", pageInfoParent); jsonOutput.set("PerPageInfo", pageInfoParent);
@@ -590,22 +602,6 @@ public class GetInfoOnPDF {
return null; return null;
} }
private void setNodePermissions(PDDocument pdfBoxDoc, ObjectNode permissionsNode) {
AccessPermission ap = pdfBoxDoc.getCurrentAccessPermission();
permissionsNode.put("Document Assembly", getPermissionState(ap.canAssembleDocument()));
permissionsNode.put("Extracting Content", getPermissionState(ap.canExtractContent()));
permissionsNode.put("Extracting for accessibility", getPermissionState(ap.canExtractForAccessibility()));
permissionsNode.put("Form Filling", getPermissionState(ap.canFillInForm()));
permissionsNode.put("Modifying", getPermissionState(ap.canModify()));
permissionsNode.put("Modifying annotations", getPermissionState(ap.canModifyAnnotations()));
permissionsNode.put("Printing", getPermissionState(ap.canPrint()));
}
private String getPermissionState(boolean state) {
return state ? "Allowed" : "Not Allowed";
}
private static void addOutlinesToArray(PDOutlineItem outline, ArrayNode arrayNode) { private static void addOutlinesToArray(PDOutlineItem outline, ArrayNode arrayNode) {
if (outline == null) return; if (outline == null) return;

View File

@@ -1,168 +0,0 @@
package stirling.software.SPDF.controller.api.security;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.util.Store;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.security.SignatureValidationRequest;
import stirling.software.SPDF.model.api.security.SignatureValidationResult;
import stirling.software.SPDF.service.CertificateValidationService;
import stirling.software.SPDF.service.CustomPDDocumentFactory;
@RestController
@RequestMapping("/api/v1/security")
@Tag(name = "Security", description = "Security APIs")
public class ValidateSignatureController {
private final CustomPDDocumentFactory pdfDocumentFactory;
private final CertificateValidationService certValidationService;
@Autowired
public ValidateSignatureController(
CustomPDDocumentFactory pdfDocumentFactory,
CertificateValidationService certValidationService) {
this.pdfDocumentFactory = pdfDocumentFactory;
this.certValidationService = certValidationService;
}
@Operation(
summary = "Validate PDF Digital Signature",
description =
"Validates the digital signatures in a PDF file against default or custom certificates. Input:PDF Output:JSON Type:SISO")
@PostMapping(value = "/validate-signature")
public ResponseEntity<List<SignatureValidationResult>> validateSignature(
@ModelAttribute SignatureValidationRequest request) throws IOException {
List<SignatureValidationResult> results = new ArrayList<>();
MultipartFile file = request.getFileInput();
// Load custom certificate if provided
X509Certificate customCert = null;
if (request.getCertFile() != null && !request.getCertFile().isEmpty()) {
try (ByteArrayInputStream certStream =
new ByteArrayInputStream(request.getCertFile().getBytes())) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
customCert = (X509Certificate) cf.generateCertificate(certStream);
} catch (CertificateException e) {
throw new RuntimeException("Invalid certificate file: " + e.getMessage());
}
}
try (PDDocument document = pdfDocumentFactory.load(file.getInputStream())) {
List<PDSignature> signatures = document.getSignatureDictionaries();
for (PDSignature sig : signatures) {
SignatureValidationResult result = new SignatureValidationResult();
try {
byte[] signedContent = sig.getSignedContent(file.getInputStream());
byte[] signatureBytes = sig.getContents(file.getInputStream());
CMSProcessable content = new CMSProcessableByteArray(signedContent);
CMSSignedData signedData = new CMSSignedData(content, signatureBytes);
Store<X509CertificateHolder> certStore = signedData.getCertificates();
SignerInformationStore signerStore = signedData.getSignerInfos();
for (SignerInformation signer : signerStore.getSigners()) {
X509CertificateHolder certHolder = (X509CertificateHolder) certStore.getMatches(signer.getSID()).iterator().next();
X509Certificate cert = new JcaX509CertificateConverter().getCertificate(certHolder);
boolean isValid = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert));
result.setValid(isValid);
// Additional validations
result.setChainValid(customCert != null
? certValidationService.validateCertificateChainWithCustomCert(cert, customCert)
: certValidationService.validateCertificateChain(cert));
result.setTrustValid(customCert != null
? certValidationService.validateTrustWithCustomCert(cert, customCert)
: certValidationService.validateTrustStore(cert));
result.setNotRevoked(!certValidationService.isRevoked(cert));
result.setNotExpired(!cert.getNotAfter().before(new Date()));
// Set basic signature info
result.setSignerName(sig.getName());
result.setSignatureDate(sig.getSignDate().getTime().toString());
result.setReason(sig.getReason());
result.setLocation(sig.getLocation());
// Set new certificate details
result.setIssuerDN(cert.getIssuerX500Principal().getName());
result.setSubjectDN(cert.getSubjectX500Principal().getName());
result.setSerialNumber(cert.getSerialNumber().toString(16)); // Hex format
result.setValidFrom(cert.getNotBefore().toString());
result.setValidUntil(cert.getNotAfter().toString());
result.setSignatureAlgorithm(cert.getSigAlgName());
// Get key size (if possible)
try {
result.setKeySize(((RSAPublicKey) cert.getPublicKey()).getModulus().bitLength());
} catch (Exception e) {
// If not RSA or error, set to 0
result.setKeySize(0);
}
result.setVersion(String.valueOf(cert.getVersion()));
// Set key usage
List<String> keyUsages = new ArrayList<>();
boolean[] keyUsageFlags = cert.getKeyUsage();
if (keyUsageFlags != null) {
String[] keyUsageLabels = {
"Digital Signature", "Non-Repudiation", "Key Encipherment",
"Data Encipherment", "Key Agreement", "Certificate Signing",
"CRL Signing", "Encipher Only", "Decipher Only"
};
for (int i = 0; i < keyUsageFlags.length; i++) {
if (keyUsageFlags[i]) {
keyUsages.add(keyUsageLabels[i]);
}
}
}
result.setKeyUsages(keyUsages);
// Check if self-signed
result.setSelfSigned(cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal()));
}
} catch (Exception e) {
result.setValid(false);
result.setErrorMessage("Signature validation failed: " + e.getMessage());
}
results.add(result);
}
}
return ResponseEntity.ok(results);
}
}

View File

@@ -69,7 +69,6 @@ public class WatermarkController {
float opacity = request.getOpacity(); float opacity = request.getOpacity();
int widthSpacer = request.getWidthSpacer(); int widthSpacer = request.getWidthSpacer();
int heightSpacer = request.getHeightSpacer(); int heightSpacer = request.getHeightSpacer();
String customColor = request.getCustomColor();
boolean convertPdfToImage = request.isConvertPDFToImage(); boolean convertPdfToImage = request.isConvertPDFToImage();
// Load the input PDF // Load the input PDF
@@ -98,8 +97,7 @@ public class WatermarkController {
widthSpacer, widthSpacer,
heightSpacer, heightSpacer,
fontSize, fontSize,
alphabet, alphabet);
customColor);
} else if ("image".equalsIgnoreCase(watermarkType)) { } else if ("image".equalsIgnoreCase(watermarkType)) {
addImageWatermark( addImageWatermark(
contentStream, contentStream,
@@ -138,8 +136,7 @@ public class WatermarkController {
int widthSpacer, int widthSpacer,
int heightSpacer, int heightSpacer,
float fontSize, float fontSize,
String alphabet, String alphabet)
String colorString)
throws IOException { throws IOException {
String resourceDir = ""; String resourceDir = "";
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA); PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
@@ -176,18 +173,7 @@ public class WatermarkController {
} }
contentStream.setFont(font, fontSize); contentStream.setFont(font, fontSize);
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
Color redactColor;
try {
if (!colorString.startsWith("#")) {
colorString = "#" + colorString;
}
redactColor = Color.decode(colorString);
} catch (NumberFormatException e) {
redactColor = Color.LIGHT_GRAY;
}
contentStream.setNonStrokingColor(redactColor);
String[] textLines = watermarkText.split("\\\\n"); String[] textLines = watermarkText.split("\\\\n");
float maxLineWidth = 0; float maxLineWidth = 0;

View File

@@ -53,13 +53,6 @@ public class SecurityWebController {
return "security/cert-sign"; return "security/cert-sign";
} }
@GetMapping("/validate-signature")
@Hidden
public String certSignVerifyForm(Model model) {
model.addAttribute("currentPage", "validate-signature");
return "security/validate-signature";
}
@GetMapping("/remove-cert-sign") @GetMapping("/remove-cert-sign")
@Hidden @Hidden
public String certUnSignForm(Model model) { public String certUnSignForm(Model model) {

View File

@@ -2,5 +2,5 @@ package stirling.software.SPDF.model;
public enum AuthenticationType { public enum AuthenticationType {
WEB, WEB,
SSO OAUTH2
} }

View File

@@ -45,9 +45,6 @@ public class AddWatermarkRequest extends PDFFile {
@Schema(description = "The height spacer between watermark elements", example = "50") @Schema(description = "The height spacer between watermark elements", example = "50")
private int heightSpacer; private int heightSpacer;
@Schema(description = "The color for watermark", defaultValue = "#d3d3d3")
private String customColor = "#d3d3d3";
@Schema(description = "Convert the redacted PDF to an image", defaultValue = "false") @Schema(description = "Convert the redacted PDF to an image", defaultValue = "false")
private boolean convertPDFToImage; private boolean convertPDFToImage;
} }

View File

@@ -1,17 +0,0 @@
package stirling.software.SPDF.model.api.security;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile;
@Data
@EqualsAndHashCode(callSuper = true)
public class SignatureValidationRequest extends PDFFile {
@Schema(description = "(Optional) file to compare PDF cert signatures against x.509 format")
private MultipartFile certFile;
}

View File

@@ -1,31 +0,0 @@
package stirling.software.SPDF.model.api.security;
import java.util.List;
import lombok.Data;
@Data
public class SignatureValidationResult {
private boolean valid;
private String signerName;
private String signatureDate;
private String reason;
private String location;
private String errorMessage;
private boolean chainValid;
private boolean trustValid;
private boolean notExpired;
private boolean notRevoked;
private String issuerDN; // Certificate issuer's Distinguished Name
private String subjectDN; // Certificate subject's Distinguished Name
private String serialNumber; // Certificate serial number
private String validFrom; // Certificate validity start date
private String validUntil; // Certificate validity end date
private String signatureAlgorithm;// Algorithm used for signing
private int keySize; // Key size in bits
private String version; // Certificate version
private List<String> keyUsages; // List of key usage purposes
private boolean isSelfSigned; // Whether the certificate is self-signed
}

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.repository; package stirling.software.SPDF.repository;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
@@ -20,6 +19,4 @@ public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username); Optional<User> findByUsername(String username);
Optional<User> findByApiKey(String apiKey); Optional<User> findByApiKey(String apiKey);
List<User> findByAuthenticationTypeIgnoreCase(String authenticationType);
} }

View File

@@ -1,157 +0,0 @@
package stirling.software.SPDF.service;
import io.github.pixee.security.BoundedLineReader;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
@Service
public class CertificateValidationService {
private KeyStore trustStore;
@PostConstruct
private void initializeTrustStore() throws Exception {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
loadMozillaCertificates();
}
private void loadMozillaCertificates() throws Exception {
try (InputStream is = getClass().getResourceAsStream("/certdata.txt")) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder certData = new StringBuilder();
boolean inCert = false;
int certCount = 0;
while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) {
if (line.startsWith("CKA_VALUE MULTILINE_OCTAL")) {
inCert = true;
certData = new StringBuilder();
continue;
}
if (inCert) {
if ("END".equals(line)) {
inCert = false;
byte[] certBytes = parseOctalData(certData.toString());
if (certBytes != null) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert =
(X509Certificate)
cf.generateCertificate(
new ByteArrayInputStream(certBytes));
trustStore.setCertificateEntry("mozilla-cert-" + certCount++, cert);
}
} else {
certData.append(line).append("\n");
}
}
}
}
}
private byte[] parseOctalData(String data) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String[] tokens = data.split("\\\\");
for (String token : tokens) {
token = token.trim();
if (!token.isEmpty()) {
baos.write(Integer.parseInt(token, 8));
}
}
return baos.toByteArray();
} catch (Exception e) {
return null;
}
}
public boolean validateCertificateChain(X509Certificate cert) {
try {
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<X509Certificate> certList = Arrays.asList(cert);
CertPath certPath = cf.generateCertPath(certList);
Set<TrustAnchor> anchors = new HashSet<>();
Enumeration<String> aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
Object trustCert = trustStore.getCertificate(aliases.nextElement());
if (trustCert instanceof X509Certificate) {
anchors.add(new TrustAnchor((X509Certificate) trustCert, null));
}
}
PKIXParameters params = new PKIXParameters(anchors);
params.setRevocationEnabled(false);
validator.validate(certPath, params);
return true;
} catch (Exception e) {
return false;
}
}
public boolean validateTrustStore(X509Certificate cert) {
try {
Enumeration<String> aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
Object trustCert = trustStore.getCertificate(aliases.nextElement());
if (trustCert instanceof X509Certificate && cert.equals(trustCert)) {
return true;
}
}
return false;
} catch (KeyStoreException e) {
return false;
}
}
public boolean isRevoked(X509Certificate cert) {
try {
cert.checkValidity();
return false;
} catch (CertificateExpiredException | CertificateNotYetValidException e) {
return true;
}
}
public boolean validateCertificateChainWithCustomCert(
X509Certificate cert, X509Certificate customCert) {
try {
cert.verify(customCert.getPublicKey());
return true;
} catch (Exception e) {
return false;
}
}
public boolean validateTrustWithCustomCert(X509Certificate cert, X509Certificate customCert) {
try {
// Compare the issuer of the signature certificate with the custom certificate
return cert.getIssuerX500Principal().equals(customCert.getSubjectX500Principal());
} catch (Exception e) {
return false;
}
}
}

View File

@@ -24,7 +24,7 @@ public class MetricsAggregatorService {
this.postHogService = postHogService; this.postHogService = postHogService;
} }
@Scheduled(fixedRate = 7200000) // Run every 2 hours @Scheduled(fixedRate = 1800000) // Run every 30 minutes
public void aggregateAndSendMetrics() { public void aggregateAndSendMetrics() {
Map<String, Object> metrics = new HashMap<>(); Map<String, Object> metrics = new HashMap<>();
Search.in(meterRegistry) Search.in(meterRegistry)
@@ -39,13 +39,6 @@ public class MetricsAggregatorService {
if (method == null || uri == null) { if (method == null || uri == null) {
return; return;
} }
if (!method.equals("GET") && !method.equals("POST")) {
return;
}
// Skip URIs that are 2 characters or shorter
if (uri.length() <= 2) {
return;
}
String key = String key =
String.format( String.format(

View File

@@ -17,18 +17,15 @@ public class PdfMetadataService {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final String stirlingPDFLabel; private final String stirlingPDFLabel;
private final UserServiceInterface userService; private final UserServiceInterface userService;
private final boolean runningEE;
@Autowired @Autowired
public PdfMetadataService( public PdfMetadataService(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@Qualifier("StirlingPDFLabel") String stirlingPDFLabel, @Qualifier("StirlingPDFLabel") String stirlingPDFLabel,
@Qualifier("runningEE") boolean runningEE,
@Autowired(required = false) UserServiceInterface userService) { @Autowired(required = false) UserServiceInterface userService) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.stirlingPDFLabel = stirlingPDFLabel; this.stirlingPDFLabel = stirlingPDFLabel;
this.userService = userService; this.userService = userService;
this.runningEE = runningEE;
} }
public PdfMetadata extractMetadataFromPdf(PDDocument pdf) { public PdfMetadata extractMetadataFromPdf(PDDocument pdf) {
@@ -64,8 +61,10 @@ public class PdfMetadataService {
String creator = stirlingPDFLabel; String creator = stirlingPDFLabel;
if (applicationProperties.getEnterpriseEdition().getCustomMetadata().isAutoUpdateMetadata() if (applicationProperties
&& runningEE) { .getEnterpriseEdition()
.getCustomMetadata()
.isAutoUpdateMetadata()) {
creator = applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator(); creator = applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator();
pdf.getDocumentInformation().setProducer(stirlingPDFLabel); pdf.getDocumentInformation().setProducer(stirlingPDFLabel);
@@ -84,8 +83,10 @@ public class PdfMetadataService {
pdf.getDocumentInformation().setModificationDate(Calendar.getInstance()); pdf.getDocumentInformation().setModificationDate(Calendar.getInstance());
String author = pdfMetadata.getAuthor(); String author = pdfMetadata.getAuthor();
if (applicationProperties.getEnterpriseEdition().getCustomMetadata().isAutoUpdateMetadata() if (applicationProperties
&& runningEE) { .getEnterpriseEdition()
.getCustomMetadata()
.isAutoUpdateMetadata()) {
author = applicationProperties.getEnterpriseEdition().getCustomMetadata().getAuthor(); author = applicationProperties.getEnterpriseEdition().getCustomMetadata().getAuthor();
if (userService != null) { if (userService != null) {

View File

@@ -105,7 +105,7 @@ public class FileToPdf {
new ByteArrayInputStream(Files.readAllBytes(zipFilePath)))) { new ByteArrayInputStream(Files.readAllBytes(zipFilePath)))) {
ZipEntry entry = zipIn.getNextEntry(); ZipEntry entry = zipIn.getNextEntry();
while (entry != null) { while (entry != null) {
Path filePath = tempUnzippedDir.resolve(sanitizeZipFilename(entry.getName())); Path filePath = tempUnzippedDir.resolve(entry.getName());
if (!entry.isDirectory()) { if (!entry.isDirectory()) {
Files.createDirectories(filePath.getParent()); Files.createDirectories(filePath.getParent());
if (entry.getName().toLowerCase().endsWith(".html") if (entry.getName().toLowerCase().endsWith(".html")
@@ -175,7 +175,7 @@ public class FileToPdf {
ZipSecurity.createHardenedInputStream(new ByteArrayInputStream(fileBytes))) { ZipSecurity.createHardenedInputStream(new ByteArrayInputStream(fileBytes))) {
ZipEntry entry = zipIn.getNextEntry(); ZipEntry entry = zipIn.getNextEntry();
while (entry != null) { while (entry != null) {
Path filePath = tempDirectory.resolve(sanitizeZipFilename(entry.getName())); Path filePath = tempDirectory.resolve(entry.getName());
if (entry.isDirectory()) { if (entry.isDirectory()) {
Files.createDirectories(filePath); // Explicitly create the directory structure Files.createDirectories(filePath); // Explicitly create the directory structure
} else { } else {
@@ -241,14 +241,4 @@ public class FileToPdf {
Files.deleteIfExists(tempOutputFile); Files.deleteIfExists(tempOutputFile);
} }
} }
static String sanitizeZipFilename(String entryName) {
if (entryName == null || entryName.trim().isEmpty()) {
return entryName;
}
while (entryName.contains("../") || entryName.contains("..\\")) {
entryName = entryName.replace("../", "").replace("..\\", "");
}
return entryName;
}
} }

View File

@@ -1,26 +0,0 @@
package stirling.software.SPDF.utils.propertyeditor;
import java.beans.PropertyEditorSupport;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
public class StringToMapPropertyEditor extends PropertyEditorSupport {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void setAsText(String text) throws IllegalArgumentException {
try {
TypeReference<HashMap<String, String>> typeRef =
new TypeReference<HashMap<String, String>>() {};
Map<String, String> map = objectMapper.readValue(text, typeRef);
setValue(map);
} catch (Exception e) {
throw new IllegalArgumentException(
"Failed to convert java.lang.String to java.util.Map");
}
}
}

View File

@@ -3,10 +3,6 @@ multipart.enabled=true
logging.level.org.springframework=WARN logging.level.org.springframework=WARN
logging.level.org.hibernate=WARN logging.level.org.hibernate=WARN
logging.level.org.eclipse.jetty=WARN logging.level.org.eclipse.jetty=WARN
#logging.level.org.springframework.security.saml2=TRACE
#logging.level.org.springframework.security=DEBUG
#logging.level.org.opensaml=DEBUG
#logging.level.stirling.software.SPDF.config.security: DEBUG
logging.level.com.zaxxer.hikari=WARN logging.level.com.zaxxer.hikari=WARN
spring.jpa.open-in-view=false spring.jpa.open-in-view=false
@@ -31,8 +27,6 @@ server.servlet.context-path=${SYSTEM_ROOTURIPATH:/}
spring.devtools.restart.enabled=true spring.devtools.restart.enabled=true
spring.devtools.livereload.enabled=true spring.devtools.livereload.enabled=true
spring.devtools.restart.exclude=stirling.software.SPDF.config.security/**
spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.encoding=UTF-8
spring.web.resources.mime-mappings.webmanifest=application/manifest+json spring.web.resources.mime-mappings.webmanifest=application/manifest+json

File diff suppressed because it is too large Load Diff

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=تجزئة المستندات PDF حسب الفص
home.splitPdfByChapters.desc=قسم مستند PDF إلى ملفات متعددة بناءً على هيكل فصوله. home.splitPdfByChapters.desc=قسم مستند PDF إلى ملفات متعددة بناءً على هيكل فصوله.
splitPdfByChapters.tags=تجزئة، فصول، علامات تبويب، تنظيم splitPdfByChapters.tags=تجزئة، فصول، علامات تبويب، تنظيم
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=إستبدال-عكس اللون replace-color.title=إستبدال-عكس اللون
replace-color.header=استبدال-عكس لون PDF replace-color.header=استبدال-عكس لون PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=تحريك إلى اليسار
multiTool.moveRight=تحريك إلى اليمين multiTool.moveRight=تحريك إلى اليمين
multiTool.delete=حذف multiTool.delete=حذف
multiTool.dragDropMessage=الصفحات المحددة multiTool.dragDropMessage=الصفحات المحددة
multiTool.undo=تراجع
multiTool.redo=إعادة إجراء
#multiTool-advert #multiTool-advert
multiTool-advert.message=هذه الميزة متوفرة في <a href="{0}">صفحة الأدوات المتعددة</a> لدينا. اطلع عليها للحصول على واجهة مستخدم محسّنة لكل صفحة وميزات إضافية! multiTool-advert.message=هذه الميزة متوفرة في <a href="{0}">صفحة الأدوات المتعددة</a> لدينا. اطلع عليها للحصول على واجهة مستخدم محسّنة لكل صفحة وميزات إضافية!
@@ -1056,7 +1050,6 @@ addPassword.submit=تشفير
#watermark #watermark
watermark.title=إضافة علامة مائية watermark.title=إضافة علامة مائية
watermark.header=إضافة علامة مائية watermark.header=إضافة علامة مائية
watermark.customColor=لون نص مخصص
watermark.selectText.1=حدد PDF لإضافة العلامة المائية إليه: watermark.selectText.1=حدد PDF لإضافة العلامة المائية إليه:
watermark.selectText.2=نص العلامة المائية: watermark.selectText.2=نص العلامة المائية:
watermark.selectText.3=حجم الخط: watermark.selectText.3=حجم الخط:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=مستوى الإشارة المرجعية: اختر مس
splitByChapters.desc.3=تمثيل البيانات الأصلية: إذا تم اختيارها، سترمز البيانات المرجعية الأصلية إلى كل PDF مجزأ. splitByChapters.desc.3=تمثيل البيانات الأصلية: إذا تم اختيارها، سترمز البيانات المرجعية الأصلية إلى كل PDF مجزأ.
splitByChapters.desc.4=سماح بالتكرار: إذا تم اختياره، يسمح بوجود معاينات متعددة في الصفحة نفسها لخلق ملفات PDF منفصلة. splitByChapters.desc.4=سماح بالتكرار: إذا تم اختياره، يسمح بوجود معاينات متعددة في الصفحة نفسها لخلق ملفات PDF منفصلة.
splitByChapters.submit=تقطيع ملف PDF splitByChapters.submit=تقطيع ملف PDF
#File Chooser
fileChooser.click=انقر هنا
fileChooser.or=أو
fileChooser.dragAndDrop=قم بسحب الملفات وإفلاتها
fileChooser.hoveredDragAndDrop=قم بسحب المفات وإفلاتها هنا
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -34,10 +34,10 @@ sizes.small=Kiçik
sizes.medium=Orta sizes.medium=Orta
sizes.large=Böyük sizes.large=Böyük
sizes.x-large=Ekstra Böyük sizes.x-large=Ekstra Böyük
error.pdfPassword=PDF sənədi şifrlənmişdir və şifr təmin edilməmişdir və ya yanlışdır. error.pdfPassword=PDF sənədi şifrələnmişdir və şifrə təmin edilməmişdir və ya yanlışdır.
delete=Sil delete=Sil
username=İstifadəçi Adı username=İstifadəçi Adı
password=Şifr password=Şifrə
welcome=Xoş gəldiniz welcome=Xoş gəldiniz
property=Xüsusiyyət property=Xüsusiyyət
black=Qara black=Qara
@@ -53,11 +53,11 @@ no=Xeyr
changedCredsMessage=Etibarnamələr dəyişdirildi! changedCredsMessage=Etibarnamələr dəyişdirildi!
notAuthenticatedMessage=İstifadəçinin kimliyi təsdiqlənməyib. notAuthenticatedMessage=İstifadəçinin kimliyi təsdiqlənməyib.
userNotFoundMessage=İstifadəçi tapılmadı. userNotFoundMessage=İstifadəçi tapılmadı.
incorrectPasswordMessage=Cari şifr yanlışdır. incorrectPasswordMessage=Cari şifrə yanlışdır.
usernameExistsMessage=İstifadəçi adı mövcuddur. usernameExistsMessage=İstifadəçi adı mövcuddur.
invalidUsernameMessage=Yanlış istifadəçi adı, istifadəçi adı sadəcə hərflərdən, rəqəmlərdən və @._+- xüsusi simvollarından ibarət ola bilər və ya düzgün email ünvanı olmalıdır. invalidUsernameMessage=Yanlış istifadəçi adı, istifadəçi adı sadəcə hərflərdən, rəqəmlərdən və @._+- xüsusi simvollarından ibarət ola bilər və ya düzgün email ünvanı olmalıdır.
invalidPasswordMessage=Şifr boş olmamalıdır, başlanğıc və sonunda boşluqdan istifadə edilməməlidir. invalidPasswordMessage=Şifrə boş olmamalıdır, başlanğıc və sonunda boşluqdan istifadə edilməməlidir.
confirmPasswordErrorMessage=Yeni Şifr və Yeni Şifri Doğrula uyğun olmalıdır. confirmPasswordErrorMessage=Yeni Şifrə və Yeni Şifrəni Doğrula uyğun olmalıdır.
deleteCurrentUserMessage=Hazırda daxil olmuş istifadəçini silmək mümkün deyil. deleteCurrentUserMessage=Hazırda daxil olmuş istifadəçini silmək mümkün deyil.
deleteUsernameExistsMessage=İstifadəçi adı mövcud deyildir və silinə bilməz. deleteUsernameExistsMessage=İstifadəçi adı mövcud deyildir və silinə bilməz.
downgradeCurrentUserMessage=Cari istifadəçinin rolunu aşağı salmaq mümkün deyil downgradeCurrentUserMessage=Cari istifadəçinin rolunu aşağı salmaq mümkün deyil
@@ -70,8 +70,8 @@ oops=Oops!
help=Yardım help=Yardım
goHomepage=Ana səhifəyə get goHomepage=Ana səhifəyə get
joinDiscord=Discord serverimizə qatıl joinDiscord=Discord serverimizə qatıl
seeDockerHub=Docker Hub-a bax seeDockerHub=Docker Hub'a bax
visitGithub=Github Repository-ə Baş Çək visitGithub=Github Repository'ə Baş Çək
donate=İanə Ver donate=İanə Ver
color=Rəng color=Rəng
sponsor=Sponsor sponsor=Sponsor
@@ -126,9 +126,9 @@ enterpriseEdition.ssoAdvert=Daha çox istifadəçi-idarəetmə xüsusiyyətləri
################# #################
# Analytics # # Analytics #
################# #################
analytics.title=Stirling PDF-i daha yaxşı etmək istəyirsinizmi? analytics.title=Stirling PDF'i daha yaxşı etmək istəyirsinizmi?
analytics.paragraph1=Stirling PDF bizə məhsulu inkişaf etdirməyə kömək etmək üçün analitikaya üstünlük verib. Biz heç bir şəxsi məlumatı və ya fayl məzmununu izləmirik. analytics.paragraph1=Stirling PDF bizə məhsulu inkişaf etdirməyə kömək etmək üçün analitikaya üstünlük verib. Biz heç bir şəxsi məlumatı və ya fayl məzmununu izləmirik.
analytics.paragraph2=Zəhmət olmasa, Stringling-PDF-ə inkişaf etməkdə və istifadəçilərimizi daha yaxşı anlamaqda yardım etmək üçün analitikanı aktivləşdirməyi nəzərə alın. analytics.paragraph2=Zəhmət olmasa, Stringling-PDF'ə inkişaf etməkdə və istifadəçilərimizi daha yaxşı anlamaqda yardım etmək üçün analitikanı aktivləşdirməyi nəzərə alın.
analytics.enable=Analitikanı aktivləşdir analytics.enable=Analitikanı aktivləşdir
analytics.disable=Analitikanı deaktivləşdir analytics.disable=Analitikanı deaktivləşdir
analytics.settings=Analitikanın parametrlərini config/settings.yml faylından dəyişə bilərsiniz. analytics.settings=Analitikanın parametrlərini config/settings.yml faylından dəyişə bilərsiniz.
@@ -141,11 +141,11 @@ navbar.darkmode=Qaranlıq Tema
navbar.language=Dillər navbar.language=Dillər
navbar.settings=Parametrlər navbar.settings=Parametrlər
navbar.allTools=Alətlər navbar.allTools=Alətlər
navbar.multiTool=Multi-Alət navbar.multiTool=Çox Alət
navbar.search=Axtar navbar.search=Axtar
navbar.sections.organize=Təşkil et navbar.sections.organize=Təşkil et
navbar.sections.convertTo=PDF-ə Çevir navbar.sections.convertTo=PDF'ə Çevir
navbar.sections.convertFrom=PDF-dən Çevir navbar.sections.convertFrom=PDF'dən Çevir
navbar.sections.security=İmza & Təhlükəsizlik navbar.sections.security=İmza & Təhlükəsizlik
navbar.sections.advance=Qabaqcıl navbar.sections.advance=Qabaqcıl
navbar.sections.edit=Bax & Redaktə et navbar.sections.edit=Bax & Redaktə et
@@ -171,11 +171,11 @@ settings.cacheInputs.help=Gələcək əməliyyatlar üçün əvvəllər istifad
changeCreds.title=Məlumatları dəyişdirin changeCreds.title=Məlumatları dəyişdirin
changeCreds.header=Hesab Məlumatlarınızı Yeniləyin changeCreds.header=Hesab Məlumatlarınızı Yeniləyin
changeCreds.changePassword=Siz standart giriş məlumatlarından istifadə edirsiniz. Zəhmət olmasa, yeni şifr daxil edin changeCreds.changePassword=Siz standart giriş məlumatlarından istifadə edirsiniz. Zəhmət olmasa, yeni şifrə daxil edin
changeCreds.newUsername=Yeni İstifadəçi Adı changeCreds.newUsername=Yeni İstifadəçi Adı
changeCreds.oldPassword=Cari Şifr changeCreds.oldPassword=Cari Şifrə
changeCreds.newPassword=Yeni Şifr changeCreds.newPassword=Yeni Şifrə
changeCreds.confirmNewPassword=Yeni Şifri Təsdiqləyin changeCreds.confirmNewPassword=Yeni Şifrəni Təsdiqləyin
changeCreds.submit=Dəyişiklikləri Təsdiqlə changeCreds.submit=Dəyişiklikləri Təsdiqlə
@@ -186,11 +186,11 @@ account.adminSettings=Admin Paramterləri - İstifadəçilər Əlavə Et və Onl
account.userControlSettings=İstifadəçi İdarəetmə Parametrləri account.userControlSettings=İstifadəçi İdarəetmə Parametrləri
account.changeUsername=İstifadəçi Adını Dəyiş account.changeUsername=İstifadəçi Adını Dəyiş
account.newUsername=Yeni İstifadəçi Adı account.newUsername=Yeni İstifadəçi Adı
account.password=Təsdiqləmə Şifri account.password=Təsdiqləmə Şifrəsi
account.oldPassword=Keçmiş Şifr account.oldPassword=Keçmiş Şifrə
account.newPassword=Yeni Şifr account.newPassword=Yeni Şifrə
account.changePassword=Şifri Dəyiş account.changePassword=Şifrəni Dəyiş
account.confirmNewPassword=Yeni Şifri Təsdiqlə account.confirmNewPassword=Yeni Şifrəni Təsdiqlə
account.signOut=Çıxış account.signOut=Çıxış
account.yourApiKey=Sizin API Açarınız account.yourApiKey=Sizin API Açarınız
account.syncTitle=Brauzer parametrlərini hesabla sinxronlaşdırın account.syncTitle=Brauzer parametrlərini hesabla sinxronlaşdırın
@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=PDF-i Fəsillərə Əsasən Böl
home.splitPdfByChapters.desc=Fəsil strukturuna əsasən PDF-i bir neçə fayla böl. home.splitPdfByChapters.desc=Fəsil strukturuna əsasən PDF-i bir neçə fayla böl.
splitPdfByChapters.tags=böl,fəsillər,əlfəcinlər,nizamla splitPdfByChapters.tags=böl,fəsillər,əlfəcinlər,nizamla
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Qabaqcıl Rəng Seçimləri replace-color.title=Qabaqcıl Rəng Seçimləri
replace-color.header=PDF-də Rəngləri Dəyiş-Tərsinə Çevir replace-color.header=PDF-də Rəngləri Dəyiş-Tərsinə Çevir
@@ -547,7 +543,7 @@ login.title=Daxil olun
login.header=Daxil olun login.header=Daxil olun
login.signin=Daxil olun login.signin=Daxil olun
login.rememberme=Məni xatırla login.rememberme=Məni xatırla
login.invalid=Etibarsız istifadəçi adı və ya şifr. login.invalid=Etibarsız istifadəçi adı və ya şifrə.
login.locked=Sizin hesabınız kilidlənmişdir. login.locked=Sizin hesabınız kilidlənmişdir.
login.signinTitle=Zəhmət olmasa, daxil olun login.signinTitle=Zəhmət olmasa, daxil olun
login.ssoSignIn=Single Sign-on vasitəsilə daxil olun login.ssoSignIn=Single Sign-on vasitəsilə daxil olun
@@ -585,8 +581,8 @@ showJS.submit=Göstər
#pdfToSinglePage #pdfToSinglePage
pdfToSinglePage.title=PDF-dən Tək Səhifəyə pdfToSinglePage.title=PDF'dən Tək Səhifəyə
pdfToSinglePage.header=PDF-dən Tək Səhifəyə pdfToSinglePage.header=PDF'dən Tək Səhifəyə
pdfToSinglePage.submit=Tək Səhifəyə Çevir pdfToSinglePage.submit=Tək Səhifəyə Çevir
@@ -605,8 +601,8 @@ getPdfInfo.downloadJson=JSON yüklə
#markdown-to-pdf #markdown-to-pdf
MarkdownToPDF.title=Markdown-dan PDF-ə MarkdownToPDF.title=Markdown'dan PDF'ə
MarkdownToPDF.header=Markdown-dan PDF-ə MarkdownToPDF.header=Markdown'dan PDF'ə
MarkdownToPDF.submit=Çevir MarkdownToPDF.submit=Çevir
MarkdownToPDF.help=İş davam edir MarkdownToPDF.help=İş davam edir
MarkdownToPDF.credit=WeasyPrint İstifadə Edir MarkdownToPDF.credit=WeasyPrint İstifadə Edir
@@ -621,8 +617,8 @@ URLToPDF.credit=WeasyPrint İstifadə Edir
#html-to-pdf #html-to-pdf
HTMLToPDF.title=HTML-dən PDF-ə HTMLToPDF.title=HTML'dən PDF'ə
HTMLToPDF.header=HTML-dən PDF-ə HTMLToPDF.header=HTML'dən PDF'ə
HTMLToPDF.help=HTML fayllarını və tərkibində mütləq html/css/images və s. olan ZIP fayllarını qəbul edir HTMLToPDF.help=HTML fayllarını və tərkibində mütləq html/css/images və s. olan ZIP fayllarını qəbul edir
HTMLToPDF.submit=Çevir HTMLToPDF.submit=Çevir
HTMLToPDF.credit=WeasyPrint İstifadə Edir HTMLToPDF.credit=WeasyPrint İstifadə Edir
@@ -660,14 +656,14 @@ AddStampRequest.submit=Təsdiqlə
#sanitizePDF #sanitizePDF
sanitizePDF.title=PDF-i Təmizlə sanitizePDF.title=PDF'i Təmizlə
sanitizePDF.header=PDF Faylını Təmizlə sanitizePDF.header=PDF Faylını Təmizlə
sanitizePDF.selectText.1=JavaScript Fəaliyyətlərini Sil sanitizePDF.selectText.1=JavaScript Fəaliyyətlərini Sil
sanitizePDF.selectText.2=Daxil Edilmiş Faylları Sil sanitizePDF.selectText.2=Daxil Edilmiş Faylları Sil
sanitizePDF.selectText.3=Metadatanı Sil sanitizePDF.selectText.3=Metadatanı Sil
sanitizePDF.selectText.4=Linkləri Sil sanitizePDF.selectText.4=Linkləri Sil
sanitizePDF.selectText.5=Şriftləri Sil sanitizePDF.selectText.5=Şriftləri Sil
sanitizePDF.submit=PDF-i Təmizlə sanitizePDF.submit=PDF'i Təmizlə
#addPageNumbers #addPageNumbers
@@ -687,7 +683,7 @@ addPageNumbers.submit=Səhifə Nömrələri əlavə edin
#auto-rename #auto-rename
auto-rename.title=Avtomatik Yenidən Adlandır auto-rename.title=Avtomatik Yenidən Adlandır
auto-rename.header=Pdf-in Adını Avtomatik Yenidən Adlandır auto-rename.header=Pdf'in Adını Avtomatik Yenidən Adlandır
auto-rename.submit=Avtomatik Yenidən Adlandır auto-rename.submit=Avtomatik Yenidən Adlandır
@@ -702,7 +698,7 @@ adjustContrast.download=Yüklə
#crop #crop
crop.title=Kəs crop.title=Kəs
crop.header=Pdf-ləri Kəs crop.header=Pdf'ləri Kəs
crop.submit=Təsdiq Et crop.submit=Təsdiq Et
@@ -726,8 +722,8 @@ pipeline.title=Pipeline
#pageLayout #pageLayout
pageLayout.title=Çoxsəhifəli Tərtibat pageLayout.title=Çoxsəhifəli Sxem
pageLayout.header=Çoxsəhifəli Tərtibat pageLayout.header=Çoxsəhifəli Sxem
pageLayout.pagesPerSheet=Vərəqdəki Səhifə Sayı: pageLayout.pagesPerSheet=Vərəqdəki Səhifə Sayı:
pageLayout.addBorder=Çərçivə Əlavə Et pageLayout.addBorder=Çərçivə Əlavə Et
pageLayout.submit=Təsdiq et pageLayout.submit=Təsdiq et
@@ -743,22 +739,22 @@ scalePages.submit=Təsdiq edin
#certSign #certSign
certSign.title=Sertifikatla İmzala certSign.title=Certificate Signing
certSign.header=PDF-i Sertifikatınızla İmzalayın (İşlənilir) certSign.header=Sign a PDF with your certificate (Work in progress)
certSign.selectPDF=İmzalamaq üçün PDF Faylı seçin: certSign.selectPDF=Select a PDF File for Signing:
certSign.jksNote=Note: Əgər sertifikatınızın tipi aşağıda göstərilməyibsə, zəhmət olmasa "Keytool command line tool" istifadə edərək onu "Java Keystroke" (.jks) faylına çevirin. Sonra, aşağıdan .jks faylını seçin. 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.selectKey=Şəxsi Açar faylınızı seçin (PKCS#8 format, .pem və ya .der ola bilər): certSign.selectKey=Select Your Private Key File (PKCS#8 format, could be .pem or .der):
certSign.selectCert=Sertifikat faylınızı seçin (X.509 format, .pem və ya .der ola bilər): certSign.selectCert=Select Your Certificate File (X.509 format, could be .pem or .der):
certSign.selectP12=PKCS#12 Keystore Faylınızı seçin (.p12 və ya .pfx) (İstəyə bağlı, əgər təmin olunarsa, şəxsi açar və sertifikatınızı ehtiva etməlidir): certSign.selectP12=Select Your PKCS#12 Keystore File (.p12 or .pfx) (Optional, If provided, it should contain your private key and certificate):
certSign.selectJKS=Java Keystore Faylınızı seçin (.jks və ya .keystore): certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore):
certSign.certType=Sertifikat Tipi certSign.certType=Certificate Type
certSign.password=Keystore və ya Şəxsi Açar daxil edin (Əgər varsa): certSign.password=Enter Your Keystore or Private Key Password (If Any):
certSign.showSig=İmzanı Göstər certSign.showSig=Show Signature
certSign.reason=Səbəb certSign.reason=Reason
certSign.location=Məkan certSign.location=Location
certSign.name=Ad certSign.name=Name
certSign.showLogo=Loqonu Göstər certSign.showLogo=Show Logo
certSign.submit=PDF-i İmzala certSign.submit=Sign PDF
#removeCertSign #removeCertSign
@@ -769,13 +765,13 @@ removeCertSign.submit=İmzanı silin
#removeBlanks #removeBlanks
removeBlanks.title=Boş Səhifələri Sil removeBlanks.title=Remove Blanks
removeBlanks.header=Boş SƏhifələri Silir removeBlanks.header=Remove Blank Pages
removeBlanks.threshold=Minimal Piksel Bəyazlığı: removeBlanks.threshold=Pixel Whiteness Threshold:
removeBlanks.thresholdDesc=Pikselin "Ağ" hesab olunması üçün minimal nə qədər bəyaz olmalı olduğunu təyin edin. 0 = Qara, 255 Ağappaq. removeBlanks.thresholdDesc=Threshold for determining how white a white pixel must be to be classed as 'White'. 0 = Black, 255 pure white.
removeBlanks.whitePercent=Bəyaz Faizi (%): removeBlanks.whitePercent=White Percent (%):
removeBlanks.whitePercentDesc=Silinmək üçün səhifənin neçə faizi "ağ" piksellərdən təşkil olunmalıdır removeBlanks.whitePercentDesc=Percent of page that must be 'white' pixels to be removed
removeBlanks.submit=Boş Səhifələri Sil removeBlanks.submit=Remove Blanks
#removeAnnotations #removeAnnotations
@@ -785,16 +781,16 @@ removeAnnotations.submit=Sil
#compare #compare
compare.title=Müqayisə Et compare.title=Compare
compare.header=PDF-ləri Müqayisə Et compare.header=Compare PDFs
compare.highlightColor.1=Önə Çıxarma Rəngi 1: compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Önə Çıxarma Rəngi 2: compare.highlightColor.2=Highlight Color 2:
compare.document.1=Sənəd 1 compare.document.1=Document 1
compare.document.2=Sənəd 2 compare.document.2=Document 2
compare.submit=Müqayisə Et compare.submit=Compare
compare.complex.message=Fayllardan biri və ya ikisi də böyük fayldır. Müqayisə effektivliyi azala bilər. compare.complex.message=One or both of the provided documents are large files, accuracy of comparison may be reduced
compare.large.file.message=Fayllardan biri və ya ikisi də işləmək üçün çox böyükdür. compare.large.file.message=One or Both of the provided documents are too large to process
compare.no.text.message=Fayllardan birində və ya ikisində də mətn məzmunu yoxdur. Zəhmət olmasa, müqayisə üçün mətn məzmunlu PDF seçin. compare.no.text.message=One or both of the selected PDFs have no text content. Please choose PDFs with text for comparison.
#BookToPDF #BookToPDF
BookToPDF.title=Kitabları və Komiksləri PDF-ə BookToPDF.title=Kitabları və Komiksləri PDF-ə
@@ -822,12 +818,12 @@ sign.save=İmzanı yadda Saxla
sign.personalSigs=Şəxsi İmzalar sign.personalSigs=Şəxsi İmzalar
sign.sharedSigs=Paylaşılan İmzalar sign.sharedSigs=Paylaşılan İmzalar
sign.noSavedSigs=Saxlanmış imza tapılmadı sign.noSavedSigs=Saxlanmış imza tapılmadı
sign.addToAll=Bütün səhiflərə əlavə et sign.addToAll=Add to all pages
sign.delete=Sil sign.delete=Delete
sign.first=İlk səhifə sign.first=First page
sign.last=Son səhifə sign.last=Last page
sign.next=Növbəti səhifə sign.next=Next page
sign.previous=Əvvəlki səhifə sign.previous=Previous page
#repair #repair
repair.title=Bərpa Et repair.title=Bərpa Et
@@ -843,37 +839,37 @@ flatten.submit=Düzləşdirin
#ScannerImageSplit #ScannerImageSplit
ScannerImageSplit.selectText.1=Bucaq Aşağı Limiti: ScannerImageSplit.selectText.1=Angle Threshold:
ScannerImageSplit.selectText.2=Şəklin fırladılması üçün lazım olan minimal mütləq bucağı təyin edir (defolt: 10). ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
ScannerImageSplit.selectText.3=Rəng Toleransı: ScannerImageSplit.selectText.3=Tolerance:
ScannerImageSplit.selectText.4=Təxmin olunan arxaplan rənginin ətrafındakı rəng fərqliliyi intervalını təyin edir (defolt: 30). ScannerImageSplit.selectText.4=Determines the range of color variation around the estimated background color (default: 30).
ScannerImageSplit.selectText.5=Minimal Sahə: ScannerImageSplit.selectText.5=Minimum Area:
ScannerImageSplit.selectText.6=Foto üçün minimal sahənin aşağı limitini təyin edir (defolt: 10000). ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000).
ScannerImageSplit.selectText.7=Minimal Kontur Sahəsi: ScannerImageSplit.selectText.7=Minimum Contour Area:
ScannerImageSplit.selectText.8=Fotonun kontur sahəsi üçün minimal aşağı limiti təyin edir ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo
ScannerImageSplit.selectText.9=Sərhəd Ölçüsü: ScannerImageSplit.selectText.9=Border Size:
ScannerImageSplit.selectText.10=Faylda ağ sərhədlərin olmasının qarşısını almaq üçün əlavə ediləcək sərhədin ölçüsünü təyin edir (defolt: 1). ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1).
ScannerImageSplit.info=Python yüklənməyib. İşə salmaq üçün Python lazımdır. ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
ocr.title=OST (OCR) / Skan Təmizləmə ocr.title=OCR / Scan Cleanup
ocr.header=Skanları Təmizlə / OST (Optik Simvol Tanınması) ocr.header=Cleanup Scans / OCR (Optical Character Recognition)
ocr.selectText.1=PDF-də aşkar olunacaq dilləri seçin (Göstərilmiş dillər hazırda aşkar olunmuşlardır): ocr.selectText.1=Select languages that are to be detected within the PDF (Ones listed are the ones currently detected):
ocr.selectText.2=OST-lənmiş PDF ilə yanaşı daxilində OST edilmiş mətn olan PDF yaradın ocr.selectText.2=Produce text file containing OCR text alongside the OCR'ed PDF
ocr.selectText.3=Əyri skan olunmuş səhifələri yerinə fırladaraq düzəldin ocr.selectText.3=Correct pages were scanned at a skewed angle by rotating them back into place
ocr.selectText.4=OST-in arxaplandakı artıq mətni aşkar etməsinin qarşısını almaq üçün səhifəni təmizləyin. (Çıxış dəyişmir) ocr.selectText.4=Clean page so its less likely that OCR will find text in background noise. (No output change)
ocr.selectText.5=OST-in arxaplandakı artıq mətni aşkar etməsinin qarşısını almaq üçün səhifəni təmizləyin, təmizləməni çıxışa verilən faylda saxlayır. ocr.selectText.5=Clean page so its less likely that OCR will find text in background noise, maintains cleanup in output.
ocr.selectText.6=Üzərində interaktiv yazı olan səhifələri nəzərə almır, yalnız şəkil olan səhifələri OST edir. ocr.selectText.6=Ignores pages that have interactive text on them, only OCRs pages that are images
ocr.selectText.7=OST-ə məcbur et, bütün orijinal mətn elementlərini silərək hər səhifəni OST edir ocr.selectText.7=Force OCR, will OCR Every page removing all original text elements
ocr.selectText.8=Normal (PDF-də mətn varsa, xəta verəcək) ocr.selectText.8=Normal (Will error if PDF contains text)
ocr.selectText.9=Əlavə Parametrlər ocr.selectText.9=Additional Settings
ocr.selectText.10=OST (OCR) Rejimi ocr.selectText.10=OCR Mode
ocr.selectText.11=OST-dən sonra şəkilləri sil (BÜTÜN şəkilləri silir, ancaq çevirmə prosesinin bir hissəsi olduqda işə yarayır) ocr.selectText.11=Remove images after OCR (Removes ALL images, only useful if part of conversion step)
ocr.selectText.12=Render Tipi (Qabaqcıl) ocr.selectText.12=Render Type (Advanced)
ocr.help=Bunu digər dillər üçün necə istifadə etmək və/və ya docker-də istifadə etməmək üçün bu dokumentasiyanı oxuyun ocr.help=Please read this documentation on how to use this for other languages and/or use not in docker
ocr.credit=Bu servis OST (OCR) üçün "OCRmyPDF" və "Tesseract" istifadə edir. ocr.credit=This service uses qpdf and Tesseract for OCR.
ocr.submit=PDF-i OST ilə işlə ocr.submit=Process PDF with OCR
#extractImages #extractImages
@@ -894,15 +890,15 @@ fileToPDF.submit=PDF-ə Çevir
#compress #compress
compress.title=Sıxışdır compress.title=Compress
compress.header=PDF-i Sıxışdır compress.header=Compress PDF
compress.credit=Bu servis PDF sıxışdırılması/Optimizasiyası üçün Ghostscript istifadə edir. compress.credit=This service uses qpdf for PDF Compress/Optimisation.
compress.selectText.1=Manual Mod - 1-dən 4-ə compress.selectText.1=Manual Mode - From 1 to 4
compress.selectText.2=Optimizasiya səviyyəsi: compress.selectText.2=Optimization level:
compress.selectText.3=4 (Mətn şəkilləri üçün yaxşı deyil) compress.selectText.3=4 (Terrible for text images)
compress.selectText.4=Avto mod - PDF-in dəqiq ölçüsünü əldə etmək üçün keyfiyyəti avtomatik tənzimləyir compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size
compress.selectText.5=Gözlənilən PDF Ölçüsü (məsələn, 25MB, 10.8MB, 25KB) compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)
compress.submit=Sıxışdır compress.submit=Compress
#Add image #Add image
@@ -923,35 +919,35 @@ merge.submit=Birləşdirin
#pdfOrganiser #pdfOrganiser
pdfOrganiser.title=Səhifə Tənzimləyicisi pdfOrganiser.title=Page Organiser
pdfOrganiser.header=PDF Səhifə Tənzimləyicisi pdfOrganiser.header=PDF Page Organiser
pdfOrganiser.submit=Səhifələri Yenidən Təşkil Edin pdfOrganiser.submit=Rearrange Pages
pdfOrganiser.mode=Rejim pdfOrganiser.mode=Mode
pdfOrganiser.mode.1=Fərdi Səhifə Düzülüşü pdfOrganiser.mode.1=Custom Page Order
pdfOrganiser.mode.2=Tərs Düzülüş pdfOrganiser.mode.2=Reverse Order
pdfOrganiser.mode.3=İkitərəfli Çeşidləmə pdfOrganiser.mode.3=Duplex Sort
pdfOrganiser.mode.4=Kitabça Çeşidləmə pdfOrganiser.mode.4=Booklet Sort
pdfOrganiser.mode.5=Yan Tikiş Kitabçasının Çeşidlənməsi pdfOrganiser.mode.5=Side Stitch Booklet Sort
pdfOrganiser.mode.6=Tək-Cüt Bölünmə pdfOrganiser.mode.6=Odd-Even Split
pdfOrganiser.mode.7=Birincini Sil pdfOrganiser.mode.7=Remove First
pdfOrganiser.mode.8=Sonuncunu Sil pdfOrganiser.mode.8=Remove Last
pdfOrganiser.mode.9=Birinci və Sonuncunu Sil pdfOrganiser.mode.9=Remove First and Last
pdfOrganiser.mode.10=Tək-Cüt Birləşdirmə pdfOrganiser.mode.10=Odd-Even Merge
pdfOrganiser.placeholder=(məs., 1,3,2 və ya 4-8,2,10-12 və ya 2n-1) pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=PDF Multi-Alət multiTool.title=PDF Multi Tool
multiTool.header=PDF Multi-Alət multiTool.header=PDF Multi Tool
multiTool.uploadPrompts=Fayl Adı multiTool.uploadPrompts=File Name
multiTool.selectAll=Hamısını Seç multiTool.selectAll=Select All
multiTool.deselectAll=Hamısını Seçməni Ləğv Et multiTool.deselectAll=Deselect All
multiTool.selectPages=Səhifə Seçimi multiTool.selectPages=Page Select
multiTool.selectedPages=Seçilmiş Səhifələr multiTool.selectedPages=Selected Pages
multiTool.page=Səhifə multiTool.page=Page
multiTool.deleteSelected=Seçilmişi Sil multiTool.deleteSelected=Delete Selected
multiTool.downloadAll=İxrac Et multiTool.downloadAll=Export
multiTool.downloadSelected=Seçilmişi İxrac Et multiTool.downloadSelected=Export Selected
multiTool.insertPageBreak=Insert Page Break multiTool.insertPageBreak=Insert Page Break
multiTool.addFile=Add File multiTool.addFile=Add File
@@ -961,12 +957,10 @@ multiTool.split=Split
multiTool.moveLeft=Move Left multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Seçilmiş Səhifə(lər) multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=Bu xüsusiyyət bizim <a href="{0}">multi-alət səhifə</a>mizdə də mövcuddur. Əlavə xüsusiyyətlər və səhifə-səhifə interfeys üçün sınaqdan keçirin! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
#view pdf #view pdf
viewPdf.title=PDF-ə baxın viewPdf.title=PDF-ə baxın
@@ -988,32 +982,32 @@ rotate.submit=Fırladın
#split-pdfs #split-pdfs
split.title=PDF-i Bölün split.title=Split PDF
split.header=PDF-i Bölün split.header=Split PDF
split.desc.1=Seçdiyiniz Nömrələr Bölmək İstədiyiniz Səhifə Nömrəsidir split.desc.1=The numbers you select are the page number you wish to do a split on
split.desc.2=Beləliklə, 1,3,7-9 Seçimi 10 Səhifəlik Sənədi 6 Ayrı PDF-ə Böləcək: split.desc.2=As such selecting 1,3,7-9 would split a 10 page document into 6 separate PDFS with:
split.desc.3=Sənəd #1: Səhifə 1 split.desc.3=Document #1: Page 1
split.desc.4=Sənəd #2: Səhifə 2 və 3 split.desc.4=Document #2: Page 2 and 3
split.desc.5=Sənəd #3: Səhifə 4, 5, 6 7 split.desc.5=Document #3: Page 4, 5, 6 and 7
split.desc.6=Sənəd #4: Səhifə 8 split.desc.6=Document #4: Page 8
split.desc.7=Sənəd #5: Səhifə 9 split.desc.7=Document #5: Page 9
split.desc.8=Sənəd #6: Səhifə 10 split.desc.8=Document #6: Page 10
split.splitPages=Bölünəcək Səhifələri Daxil Edin: split.splitPages=Enter pages to split on:
split.submit=Bölün split.submit=Split
#merge #merge
imageToPDF.title=Şəkli PDF imageToPDF.title=Image to PDF
imageToPDF.header=Şəkli PDF imageToPDF.header=Image to PDF
imageToPDF.submit=Çevir imageToPDF.submit=Convert
imageToPDF.selectLabel=Şəkil Uyğunluğu Seçimləri imageToPDF.selectLabel=Image Fit Options
imageToPDF.fillPage=Səhifəni Doldur imageToPDF.fillPage=Fill Page
imageToPDF.fitDocumentToImage=Şəklə Uyğun Səhifə imageToPDF.fitDocumentToImage=Fit Page to Image
imageToPDF.maintainAspectRatio=Aspekt Nisbətlərini Qoruyun imageToPDF.maintainAspectRatio=Maintain Aspect Ratios
imageToPDF.selectText.2=PDF-i Avtomatik Fırlat imageToPDF.selectText.2=Auto rotate PDF
imageToPDF.selectText.3=Çoxsaylı Fayl Məntiqi (Yalnız Birdən Çox Şəkil İlə İşləyərkən Aktivdir) imageToPDF.selectText.3=Multi file logic (Only enabled if working with multiple images)
imageToPDF.selectText.4=Tək Bir PDF-ə Birləşdir imageToPDF.selectText.4=Merge into single PDF
imageToPDF.selectText.5=Ayrı PDF-lərə Çevirin imageToPDF.selectText.5=Convert to separate PDFs
#pdfToImage #pdfToImage
@@ -1032,98 +1026,97 @@ pdfToImage.info=Python Yüklü Deyil.WebP Çevirməsi Üçün Vacibdir
#addPassword #addPassword
addPassword.title=Şifr Əlavə Et addPassword.title=Add Password
addPassword.header=Şifr Əlavə Et (Şifrləmə) addPassword.header=Add password (Encrypt)
addPassword.selectText.1=Şifrlənəcək PDF-i seç addPassword.selectText.1=Select PDF to encrypt
addPassword.selectText.2=İstifadəçi Şifri addPassword.selectText.2=User Password
addPassword.selectText.3=Şifrləmə Açarı Uzunluğu addPassword.selectText.3=Encryption Key Length
addPassword.selectText.4=Böyük dəyərlər daha güclüdür, lakin kiçik dəyərlərin uyğunluğu yüksəkdir. addPassword.selectText.4=Higher values are stronger, but lower values have better compatibility.
addPassword.selectText.5=Təyin olunacaq icazə (Sahib (Owner) Şifri ilə birgə istifadə olunması tövsiyə olunur.) addPassword.selectText.5=Permissions to set (Recommended to be used along with Owner password)
addPassword.selectText.6=Sənədin strukturunun dəyişilməsinin qarşısını al addPassword.selectText.6=Prevent assembly of document
addPassword.selectText.7=Məzmun xaric edilməsinin qarşısını al addPassword.selectText.7=Prevent content extraction
addPassword.selectText.8=Əlçatanlıq üçün xaricetmənin qarşısını al addPassword.selectText.8=Prevent extraction for accessibility
addPassword.selectText.9=Anketin doldurulmasının qarşısını al addPassword.selectText.9=Prevent filling in form
addPassword.selectText.10=Modifikasiyanın qarşısını al addPassword.selectText.10=Prevent modification
addPassword.selectText.11=Sitat modifikasiyasının qarşısını al addPassword.selectText.11=Prevent annotation modification
addPassword.selectText.12=Çap etmənin qarşısını al addPassword.selectText.12=Prevent printing
addPassword.selectText.13=Müxtəlif formatların çap edilməsinin qarşısını al addPassword.selectText.13=Prevent printing different formats
addPassword.selectText.14=Sahib Şifri addPassword.selectText.14=Owner Password
addPassword.selectText.15=Sənəd açıldıqdan sonra onunla nə edilə biləcəyini limitləndir (Bütün oxuyucular dəstəkləmir) addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
addPassword.selectText.16=Sənədin özünün açılmağını limitləndirir addPassword.selectText.16=Restricts the opening of the document itself
addPassword.submit=Şifrlə addPassword.submit=Encrypt
#watermark #watermark
watermark.title=Watermark Əlavə Et watermark.title=Add Watermark
watermark.header=Watermark Əlavə Et watermark.header=Add Watermark
watermark.customColor=Fərdi Mətn Rəngi watermark.selectText.1=Select PDF to add watermark to:
watermark.selectText.1=Watermark əlavə olunacaq PDF-i seç watermark.selectText.2=Watermark Text:
watermark.selectText.2=Watermark Mətni: watermark.selectText.3=Font Size:
watermark.selectText.3=Şrift Ölçüsü: watermark.selectText.4=Rotation (0-360):
watermark.selectText.4=Fırlatma (0-360): watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
watermark.selectText.5=enBoşluq (Üfuqi olaraq watermark-lar arasındakı məsafə): watermark.selectText.6=heightSpacer (Space between each watermark vertically):
watermark.selectText.6=uzunluqBoşluq (Şaquli olaraq watermark-lar arasındakı məsafə): watermark.selectText.7=Opacity (0% - 100%):
watermark.selectText.7=Şəffaflıq (0% - 100%): watermark.selectText.8=Watermark Type:
watermark.selectText.8=Watermark Tipi: watermark.selectText.9=Watermark Image:
watermark.selectText.9=Watermark Şəkili: watermark.selectText.10=Convert PDF to PDF-Image
watermark.selectText.10=PDF-i PDF-Şəkil-ə çevir watermark.submit=Add Watermark
watermark.submit=Watermark Əlavə Et watermark.type.1=Text
watermark.type.1=Mətn watermark.type.2=Image
watermark.type.2=Şəkil
#Change permissions #Change permissions
permissions.title=İcazələri Dəyişdir permissions.title=Change Permissions
permissions.header=İcazələri Dəyişdir permissions.header=Change Permissions
permissions.warning=Bu İcazələrin Dəyişməz Olması İlə Bağlı Xəbərdarlıq Edərək, Onları Parol Əlavə Et Səhifəsi Vasitəsilə Parolla Təyin Etmək Tövsiyə Olunur. permissions.warning=Warning to have these permissions be unchangeable it is recommended to set them with a password via the add-password page
permissions.selectText.1=İcazələri Dəyişdirmək Üçün PDF-i Seç permissions.selectText.1=Select PDF to change permissions
permissions.selectText.2=Tənzimlənmiş İcazələr permissions.selectText.2=Permissions to set
permissions.selectText.3=Sənədin Yığılmasının Qarşısını Al permissions.selectText.3=Prevent assembly of document
permissions.selectText.4=Məzmunun Çıxarılmasının Qarşısını Al permissions.selectText.4=Prevent content extraction
permissions.selectText.5=Əlçatanlıq Üçün Çıxarılmasının Qarşısını Alın permissions.selectText.5=Prevent extraction for accessibility
permissions.selectText.6=Formanın Doldurulmasının Qarşısını Alır permissions.selectText.6=Prevent filling in form
permissions.selectText.7=Modifikasiyanın Qarşısını Al permissions.selectText.7=Prevent modification
permissions.selectText.8=Annotasiyanın Dəyişdirilməsinin Qarşısını Almaq permissions.selectText.8=Prevent annotation modification
permissions.selectText.9=Çapın Qarşısını Al permissions.selectText.9=Prevent printing
permissions.selectText.10=Fərqli Formatlarda Çapın Qarşısını Al permissions.selectText.10=Prevent printing different formats
permissions.submit=Dəyiş permissions.submit=Change
#remove password #remove password
removePassword.title=Şifri Sil removePassword.title=Remove password
removePassword.header=Şifri Sil (Deşifr) removePassword.header=Remove password (Decrypt)
removePassword.selectText.1=Deşifr Üçün PDF-i Seç removePassword.selectText.1=Select PDF to Decrypt
removePassword.selectText.2=Şifr removePassword.selectText.2=Password
removePassword.submit=Sil removePassword.submit=Remove
#changeMetadata #changeMetadata
changeMetadata.title=Metadata-nı Dəyiş changeMetadata.title=Change Metadata
changeMetadata.header=Metadata-nı Dəyiş changeMetadata.header=Change Metadata
changeMetadata.selectText.1=Dəyişmək istədiyiniz dəyişənləri redaktə edin changeMetadata.selectText.1=Please edit the variables you wish to change
changeMetadata.selectText.2=Bütün Metadata-nı Sil changeMetadata.selectText.2=Delete all metadata
changeMetadata.selectText.3=Fərdi Metadatanı göstərin: changeMetadata.selectText.3=Show Custom Metadata:
changeMetadata.author=Müəllif: changeMetadata.author=Author:
changeMetadata.creationDate=Yaradılma Tarixi (yyyy/MM/dd HH:mm:ss): changeMetadata.creationDate=Creation Date (yyyy/MM/dd HH:mm:ss):
changeMetadata.creator=Yaradıcı: changeMetadata.creator=Creator:
changeMetadata.keywords=Açar Sözlər: changeMetadata.keywords=Keywords:
changeMetadata.modDate=Dəyişiklik Tarixi (yyyy/MM/dd HH:mm:ss): changeMetadata.modDate=Modification Date (yyyy/MM/dd HH:mm:ss):
changeMetadata.producer=İstehsalçı: changeMetadata.producer=Producer:
changeMetadata.subject=Mövzu: changeMetadata.subject=Subject:
changeMetadata.trapped=Tələ: changeMetadata.trapped=Trapped:
changeMetadata.selectText.4=Digər Metadata: changeMetadata.selectText.4=Other Metadata:
changeMetadata.selectText.5=Xüsusi Metadata girişi əlavə edin changeMetadata.selectText.5=Add Custom Metadata Entry
changeMetadata.submit=Dəyiş changeMetadata.submit=Change
#pdfToPDFA #pdfToPDFA
pdfToPDFA.title=PDF-i PDF/A-ya pdfToPDFA.title=PDF To PDF/A
pdfToPDFA.header=PDF-i PDF/A-ya pdfToPDFA.header=PDF To PDF/A
pdfToPDFA.credit=Bu Servis PDF/A Çevirmək Üçün ghostscript İşlədir pdfToPDFA.credit=This service uses qpdf for PDF/A conversion
pdfToPDFA.submit=Çevir pdfToPDFA.submit=Convert
pdfToPDFA.tip=Hazırda Birdən Çox Giriş Üçün İşləmir pdfToPDFA.tip=Currently does not work for multiple inputs at once
pdfToPDFA.outputFormat=Çıxış Formatı pdfToPDFA.outputFormat=Output format
pdfToPDFA.pdfWithDigitalSignature=PDF Rəqəmsal İmza Ehtiva Edir.Bu, növbəti addımda silinəcək. pdfToPDFA.pdfWithDigitalSignature=The PDF contains a digital signature. This will be removed in the next step.
#PDFToWord #PDFToWord
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Səviyyəsi: Bölmə üçün istifadə ediləcə
splitByChapters.desc.3=Metadatanı daxil edin: Əgər yoxlanılıbsa, orijinal PDF-in metadatası hər bir bölünmüş PDF-ə daxil ediləcək. splitByChapters.desc.3=Metadatanı daxil edin: Əgər yoxlanılıbsa, orijinal PDF-in metadatası hər bir bölünmüş PDF-ə daxil ediləcək.
splitByChapters.desc.4=Allow Duplicates: Dublikatlara icazə verin: Əgər işarələnərsə, eyni səhifədə birdən çox bookmarka ayrı-ayrı PDF sənədləri yaratmağa icazə verin. splitByChapters.desc.4=Allow Duplicates: Dublikatlara icazə verin: Əgər işarələnərsə, eyni səhifədə birdən çox bookmarka ayrı-ayrı PDF sənədləri yaratmağa icazə verin.
splitByChapters.submit=PDF-i Ayır splitByChapters.submit=PDF-i Ayır
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Buraxılışlar
releases.title=Buraxılış Qeydləri
releases.header=Buraxılış Qeydləri
releases.current.version=Hazırki Buraxılış
releases.note=Buraxılış Qeydləri yalnız ingiliscə mövcuddur
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Разделете PDF по глави
home.splitPdfByChapters.desc=Разделете PDF на множество файлове въз основа на неговата структура на глави. home.splitPdfByChapters.desc=Разделете PDF на множество файлове въз основа на неговата структура на глави.
splitPdfByChapters.tags=разделяне, глави, отметки, организиране splitPdfByChapters.tags=разделяне, глави, отметки, организиране
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Замени-инвертиране-на-цвят replace-color.title=Замени-инвертиране-на-цвят
replace-color.header=Замяна-инвертиране на цвят PDF replace-color.header=Замяна-инвертиране на цвят PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Шифроване
#watermark #watermark
watermark.title=Добавяне на воден знак watermark.title=Добавяне на воден знак
watermark.header=Добавяне на воден знак watermark.header=Добавяне на воден знак
watermark.customColor=Персонализиран цвят на текста
watermark.selectText.1=Изберете PDF, към който да добавите воден знак: watermark.selectText.1=Изберете PDF, към който да добавите воден знак:
watermark.selectText.2=Текст на воден знак: watermark.selectText.2=Текст на воден знак:
watermark.selectText.3=Размер на шрифта: watermark.selectText.3=Размер на шрифта:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Ниво на отметка: Изберете нивот
splitByChapters.desc.3=Включване на метаданни: Ако е отметнато, метаданните на оригиналния PDF ще бъдат включени във всеки разделен PDF. splitByChapters.desc.3=Включване на метаданни: Ако е отметнато, метаданните на оригиналния PDF ще бъдат включени във всеки разделен PDF.
splitByChapters.desc.4=Разрешаване на дубликати: Ако е отметнато, позволява множество отметки на една и съща страница за създаване на отделни PDF файлове. splitByChapters.desc.4=Разрешаване на дубликати: Ако е отметнато, позволява множество отметки на една и съща страница за създаване на отделни PDF файлове.
splitByChapters.submit=Разделяне на PDF splitByChapters.submit=Разделяне на PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Divideix PDF per Capítols
home.splitPdfByChapters.desc=Divideix un PDF en múltiples fitxers segons la seva estructura de capítols. home.splitPdfByChapters.desc=Divideix un PDF en múltiples fitxers segons la seva estructura de capítols.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Reemplaça-Inverteix-Color replace-color.title=Reemplaça-Inverteix-Color
replace-color.header=Reemplaça-Inverteix Color en PDF replace-color.header=Reemplaça-Inverteix Color en PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Encripta
#watermark #watermark
watermark.title=Afegir Marca d'Aigua watermark.title=Afegir Marca d'Aigua
watermark.header=Afegir Marca d'Aigua watermark.header=Afegir Marca d'Aigua
watermark.customColor=Color de Text Personalitzat
watermark.selectText.1=Selecciona el PDF per afegir la Marca d'Aigua: watermark.selectText.1=Selecciona el PDF per afegir la Marca d'Aigua:
watermark.selectText.2=Text de la Marca d'Aigua watermark.selectText.2=Text de la Marca d'Aigua
watermark.selectText.3=Mida de la Font: watermark.selectText.3=Mida de la Font:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Nivell de Marcadors: Tria el nivell de marcadors que s'ut
splitByChapters.desc.3=Incloure Metadades: Si està marcat, les metadades del PDF original s'inclouran en cada PDF dividit. splitByChapters.desc.3=Incloure Metadades: Si està marcat, les metadades del PDF original s'inclouran en cada PDF dividit.
splitByChapters.desc.4=Permetre Duplicats: Si està marcat, permet diversos marcadors a la mateixa pàgina per crear PDFs separats. splitByChapters.desc.4=Permetre Duplicats: Si està marcat, permet diversos marcadors a la mateixa pàgina per crear PDFs separats.
splitByChapters.submit=Divideix PDF splitByChapters.submit=Divideix PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Rozdělit PDF podle kapitol
home.splitPdfByChapters.desc=Rozdělit PDF do více souborů na základě jeho struktury kapitol. home.splitPdfByChapters.desc=Rozdělit PDF do více souborů na základě jeho struktury kapitol.
splitPdfByChapters.tags=rozdělení, kapitoly, zápisky, organizace splitPdfByChapters.tags=rozdělení, kapitoly, zápisky, organizace
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Nahradit inverzní barvu PDF replace-color.header=Nahradit inverzní barvu PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Šifrovat
#watermark #watermark
watermark.title=Přidat vodoznak watermark.title=Přidat vodoznak
watermark.header=Přidat vodoznak watermark.header=Přidat vodoznak
watermark.customColor=Vlastní barva textu
watermark.selectText.1=Vyberte PDF, ke kterému chcete přidat vodoznak: watermark.selectText.1=Vyberte PDF, ke kterému chcete přidat vodoznak:
watermark.selectText.2=Text vodoznaku: watermark.selectText.2=Text vodoznaku:
watermark.selectText.3=Velikost písma: watermark.selectText.3=Velikost písma:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Úroveň záhlaví: Zvolte úroveň záhlaví pro použit
splitByChapters.desc.3=Zahrnout metadatů: Pokud je zaškrtnuto, původní metadata PDF souboru budou zahrnuty do každého odděleného PDF souboru. splitByChapters.desc.3=Zahrnout metadatů: Pokud je zaškrtnuto, původní metadata PDF souboru budou zahrnuty do každého odděleného PDF souboru.
splitByChapters.desc.4=Povolit duplicitní záznamy: Pokud je zaškrtnuto, návštěvníci mohou vytvořit samostatné PDF soubory z více záhlaví na stejné straně. splitByChapters.desc.4=Povolit duplicitní záznamy: Pokud je zaškrtnuto, návštěvníci mohou vytvořit samostatné PDF soubory z více záhlaví na stejné straně.
splitByChapters.submit=Podělit se PDF splitByChapters.submit=Podělit se PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Partitioner PDF efter kapitler
home.splitPdfByChapters.desc=Partitioner en PDF i flere filer baseret på dens kapitelstruktur. home.splitPdfByChapters.desc=Partitioner en PDF i flere filer baseret på dens kapitelstruktur.
splitPdfByChapters.tags=partitionering,kapitler,merker,organisering splitPdfByChapters.tags=partitionering,kapitler,merker,organisering
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Erstat-omgivende Farve PDF replace-color.header=Erstat-omgivende Farve PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Kryptér
#watermark #watermark
watermark.title=Tilføj Vandmærke watermark.title=Tilføj Vandmærke
watermark.header=Tilføj Vandmærke watermark.header=Tilføj Vandmærke
watermark.customColor=Brugerdefineret Tekstfarve
watermark.selectText.1=Vælg PDF til at tilføje vandmærke: watermark.selectText.1=Vælg PDF til at tilføje vandmærke:
watermark.selectText.2=Vandmærketekst: watermark.selectText.2=Vandmærketekst:
watermark.selectText.3=Skriftstørrelse: watermark.selectText.3=Skriftstørrelse:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bogmærke niveau: Vælg nivået af bogmærker, der skal b
splitByChapters.desc.3=Inkluder metadata: Hvis markeret, vil den originale PDF's metadata inkluderes i hver splitterdels PDF. splitByChapters.desc.3=Inkluder metadata: Hvis markeret, vil den originale PDF's metadata inkluderes i hver splitterdels PDF.
splitByChapters.desc.4=Tillad duplikater: Hvis markeret, tillader det flere bogmærker på samme side til at oprette separate PDF'er. splitByChapters.desc.4=Tillad duplikater: Hvis markeret, tillader det flere bogmærker på samme side til at oprette separate PDF'er.
splitByChapters.submit=Splitter PDF splitByChapters.submit=Splitter PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -146,8 +146,8 @@ navbar.search=Suche
navbar.sections.organize=Organisieren navbar.sections.organize=Organisieren
navbar.sections.convertTo=In PDF konvertieren navbar.sections.convertTo=In PDF konvertieren
navbar.sections.convertFrom=Konvertieren von PDF navbar.sections.convertFrom=Konvertieren von PDF
navbar.sections.security=Signieren und Sicherheit navbar.sections.security=Zeichen und Sicherheit
navbar.sections.advance=Erweiterte Funktionen navbar.sections.advance=Fortschrittlich
navbar.sections.edit=Anzeigen und Bearbeiten navbar.sections.edit=Anzeigen und Bearbeiten
navbar.sections.popular=Beliebt navbar.sections.popular=Beliebt
@@ -248,7 +248,7 @@ database.fileNullOrEmpty=Datei darf nicht null oder leer sein
database.failedImportFile=Dateiimport fehlgeschlagen database.failedImportFile=Dateiimport fehlgeschlagen
session.expired=Ihre Sitzung ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es erneut. session.expired=Ihre Sitzung ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es erneut.
session.refreshPage=Seite aktualisieren session.refreshPage=Refresh Page
############# #############
# HOME-PAGE # # HOME-PAGE #
@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=PDF-Datei nach Kapiteln aufteilen
home.splitPdfByChapters.desc=Aufteilung einer PDF-Datei in mehrere Dateien auf Basis der Kapitelstruktur. home.splitPdfByChapters.desc=Aufteilung einer PDF-Datei in mehrere Dateien auf Basis der Kapitelstruktur.
splitPdfByChapters.tags=aufteilen,kapitel,lesezeichen,organisieren splitPdfByChapters.tags=aufteilen,kapitel,lesezeichen,organisieren
home.validateSignature.title=PDF-Signatur überprüfen
home.validateSignature.desc=Digitale Signaturen und Zertifikate in PDF-Dokumenten überprüfen
validateSignature.tags=signature,verify,validate,pdf,digitale signatur,signatur validieren,überprüfen,Zertifikat,cert
#replace-invert-color #replace-invert-color
replace-color.title=Farbe Ersetzen-Invertieren replace-color.title=Farbe Ersetzen-Invertieren
replace-color.header=Farb-PDF Ersetzen-Invertieren replace-color.header=Farb-PDF Ersetzen-Invertieren
@@ -822,12 +818,12 @@ sign.save=Signature speichern
sign.personalSigs=Persönliche Signaturen sign.personalSigs=Persönliche Signaturen
sign.sharedSigs=Geteilte Signaturen sign.sharedSigs=Geteilte Signaturen
sign.noSavedSigs=Es wurden keine gespeicherten Signaturen gefunden sign.noSavedSigs=Es wurden keine gespeicherten Signaturen gefunden
sign.addToAll=Zu allen Seiten hinzufügen sign.addToAll=Add to all pages
sign.delete=Löschen sign.delete=Delete
sign.first=Erste Seite sign.first=First page
sign.last=Letzte Seite sign.last=Last page
sign.next=Nächste Seite sign.next=Next page
sign.previous=Vorherige Seite sign.previous=Previous page
#repair #repair
repair.title=Reparieren repair.title=Reparieren
@@ -953,17 +949,15 @@ multiTool.deleteSelected=Auswahl löschen
multiTool.downloadAll=Downloaden multiTool.downloadAll=Downloaden
multiTool.downloadSelected=Auswahl downloaden multiTool.downloadSelected=Auswahl downloaden
multiTool.insertPageBreak=Seitenumbruch einfügen multiTool.insertPageBreak=Insert Page Break
multiTool.addFile=Datei hinzufügen multiTool.addFile=Add File
multiTool.rotateLeft=Nach links drehen multiTool.rotateLeft=Rotate Left
multiTool.rotateRight=Nach rechts drehen multiTool.rotateRight=Rotate Right
multiTool.split=Teilen multiTool.split=Split
multiTool.moveLeft=Nach links verschieben multiTool.moveLeft=Move Left
multiTool.moveRight=Nach rechts verschieben multiTool.moveRight=Move Right
multiTool.delete=Löschen multiTool.delete=Delete
multiTool.dragDropMessage=Ausgewählte Seite(n) multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Rückgängig machen
multiTool.redo=Wiederherstellen
#multiTool-advert #multiTool-advert
multiTool-advert.message=Diese Funktion ist auch auf unserer <a href="{0}">PDF-Multitool-Seite</a> verfügbar. Probieren Sie sie aus, denn sie bietet eine verbesserte Benutzeroberfläche und zusätzliche Funktionen! multiTool-advert.message=Diese Funktion ist auch auf unserer <a href="{0}">PDF-Multitool-Seite</a> verfügbar. Probieren Sie sie aus, denn sie bietet eine verbesserte Benutzeroberfläche und zusätzliche Funktionen!
@@ -1056,7 +1050,6 @@ addPassword.submit=Verschlüsseln
#watermark #watermark
watermark.title=Wasserzeichen hinzufügen watermark.title=Wasserzeichen hinzufügen
watermark.header=Wasserzeichen hinzufügen watermark.header=Wasserzeichen hinzufügen
watermark.customColor=Benutzerdefinierte Textfarbe
watermark.selectText.1=PDF auswählen, dem ein Wasserzeichen hinzugefügt werden soll: watermark.selectText.1=PDF auswählen, dem ein Wasserzeichen hinzugefügt werden soll:
watermark.selectText.2=Wasserzeichen Text: watermark.selectText.2=Wasserzeichen Text:
watermark.selectText.3=Schriftgröße: watermark.selectText.3=Schriftgröße:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Lesezeichenebene: Wählen Sie die Ebene der Lesezeichen,
splitByChapters.desc.3=Metadaten einschließen: Wenn diese Option aktiviert ist, werden die Metadaten der ursprünglichen PDF-Datei in jede aufgeteilte PDF-Datei übernommen. splitByChapters.desc.3=Metadaten einschließen: Wenn diese Option aktiviert ist, werden die Metadaten der ursprünglichen PDF-Datei in jede aufgeteilte PDF-Datei übernommen.
splitByChapters.desc.4=Duplikate erlauben: Wenn diese Option aktiviert ist, können mehrere Lesezeichen auf derselben Seite separate PDF Dateien erstellen. splitByChapters.desc.4=Duplikate erlauben: Wenn diese Option aktiviert ist, können mehrere Lesezeichen auf derselben Seite separate PDF Dateien erstellen.
splitByChapters.submit=PDF teilen splitByChapters.submit=PDF teilen
#File Chooser
fileChooser.click=Klicken
fileChooser.or=oder
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Datei(en) hierhin Ziehen & Fallenlassen
#release notes
releases.footer=Veröffentlichungen
releases.title=Versionshinweise
releases.header=Versionshinweise
releases.current.version=Aktuelle Version
releases.note=Versionshinweise sind nur auf Englisch verfügbar
#Validate Signature
validateSignature.title=PDF-Signaturen überprüfen
validateSignature.header=Digitale Signaturen überprüfen
validateSignature.selectPDF=Signierte PDF-Datei auswählen
validateSignature.submit=Signaturen überprüfen
validateSignature.results=Gültigkeitsprüfungsergebnisse
validateSignature.status=Status
validateSignature.signer=Unterzeichner
validateSignature.date=Datum
validateSignature.reason=Grund
validateSignature.location=Ort
validateSignature.noSignatures=Keine digitalen Signaturen in diesem Dokument gefunden
validateSignature.status.valid=Gültig
validateSignature.status.invalid=Ungültig
validateSignature.chain.invalid=Zertifikatskettenprüfung fehlgeschlagen - kann die Identität des Unterzeichners nicht verifizieren
validateSignature.trust.invalid=Zertifikat nicht im Truststore - Quelle kann nicht verifiziert werden
validateSignature.cert.expired=Zertifikat ist abgelaufen
validateSignature.cert.revoked=Zertifikat wurde widerrufen
validateSignature.signature.info=Signaturinformationen
validateSignature.signature=Signatur
validateSignature.signature.mathValid=Signatur ist mathematisch gültig ABER:
validateSignature.selectCustomCert=Benutzerdefinierte Zertifikatsdatei X.509 (Optional)
validateSignature.cert.info=Zertifikat Details
validateSignature.cert.issuer=Aussteller
validateSignature.cert.subject=Betreff
validateSignature.cert.serialNumber=Seriennummer
validateSignature.cert.validFrom=Gültig von
validateSignature.cert.validUntil=Gültig bis
validateSignature.cert.algorithm=Algorithmus
validateSignature.cert.keySize=Schlüsselgröße
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Schlüsselverwendung
validateSignature.cert.selfSigned=Selbstsigniert
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Διχοτομία PDF ανά Περιγραφές
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=διχοτομία,περιγραφές,κεφάλαια,συνορία splitPdfByChapters.tags=διχοτομία,περιγραφές,κεφάλαια,συνορία
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Αντικατάσταση-Αντίστροφη Παθωμένη Πίντσουρ replace-color.header=Αντικατάσταση-Αντίστροφη Παθωμένη Πίντσουρ
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Κρυπτογράφηση
#watermark #watermark
watermark.title=Προσθήκη Υδατογραφήματος watermark.title=Προσθήκη Υδατογραφήματος
watermark.header=Προσθήκη Υδατογραφήματος watermark.header=Προσθήκη Υδατογραφήματος
watermark.customColor=Προσαρμοσμένο χρώμα κειμένου
watermark.selectText.1=Επιλέξτε PDF για την προσθήκη του υδατογραφήματος: watermark.selectText.1=Επιλέξτε PDF για την προσθήκη του υδατογραφήματος:
watermark.selectText.2=Κείμενο Υδατογραφήματος: watermark.selectText.2=Κείμενο Υδατογραφήματος:
watermark.selectText.3=Μέγεθος Κειμένου: watermark.selectText.3=Μέγεθος Κειμένου:
watermark.selectText.4=Περιστροφή (0-360): watermark.selectText.4=Περιστροφή (0-360):
watermark.selectText.5=Width Spacer (Κενό μεταξύ κάθε υδατογραφήματος οριζόντια): watermark.selectText.5=widthSpacer (Κενό μεταξύ κάθε υδατογραφήματος οριζόντια):
watermark.selectText.6=Height Spacer (Κενό μεταξύ κάθε υδατογραφήματος κάθετα): watermark.selectText.6=heightSpacer (Κενό μεταξύ κάθε υδατογραφήματος κάθετα):
watermark.selectText.7=Αδιαφάνεια (Opacity) (0% - 100%): watermark.selectText.7=Αδιαφάνεια (Opacity) (0% - 100%):
watermark.selectText.8=Τύπος Υδατογραφήματος: watermark.selectText.8=Τύπος Υδατογραφήματος:
watermark.selectText.9=Εικόνα Υδατογραφήματος: watermark.selectText.9=Εικόνα Υδατογραφήματος:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Επίπεδο Σήμανσης Σκέψης: Επιλέ
splitByChapters.desc.3=Πρόσθεση Metadata: Αν επεξεργαστείται, οι αρχικές metadata του PDF θα προστεθούν σε κάθε διαλυμένο PDF. splitByChapters.desc.3=Πρόσθεση Metadata: Αν επεξεργαστείται, οι αρχικές metadata του PDF θα προστεθούν σε κάθε διαλυμένο PDF.
splitByChapters.desc.4=Διάλυση Παρόντων Τίτλων Επιπέδου: Αν επεξεργαστείται, επιτρέπει τη δημιουργία αποκοπών PDF με βάση πλήρως καθορισμένους σήμαντες έδρας. splitByChapters.desc.4=Διάλυση Παρόντων Τίτλων Επιπέδου: Αν επεξεργαστείται, επιτρέπει τη δημιουργία αποκοπών PDF με βάση πλήρως καθορισμένους σήμαντες έδρας.
splitByChapters.submit=Διαλύστε το PDF splitByChapters.submit=Διαλύστε το PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -73,7 +73,7 @@ joinDiscord=Join our Discord server
seeDockerHub=See Docker Hub seeDockerHub=See Docker Hub
visitGithub=Visit Github Repository visitGithub=Visit Github Repository
donate=Donate donate=Donate
color=Colour color=Color
sponsor=Sponsor sponsor=Sponsor
info=Info info=Info
pro=Pro pro=Pro
@@ -419,9 +419,9 @@ home.auto-rename.title=Auto Rename PDF File
home.auto-rename.desc=Auto renames a PDF file based on its detected header home.auto-rename.desc=Auto renames a PDF file based on its detected header
auto-rename.tags=auto-detect,header-based,organize,relabel auto-rename.tags=auto-detect,header-based,organize,relabel
home.adjust-contrast.title=Adjust Colours/Contrast home.adjust-contrast.title=Adjust Colors/Contrast
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
adjust-contrast.tags=color-correction,tune,modify,enhance,colour-correction adjust-contrast.tags=color-correction,tune,modify,enhance
home.crop.title=Crop PDF home.crop.title=Crop PDF
home.crop.desc=Crop a PDF to reduce its size (maintains text!) home.crop.desc=Crop a PDF to reduce its size (maintains text!)
@@ -488,11 +488,11 @@ overlay-pdfs.tags=Overlay
home.split-by-sections.title=Split PDF by Sections home.split-by-sections.title=Split PDF by Sections
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
split-by-sections.tags=Section Split, Divide, Customize,Customise split-by-sections.tags=Section Split, Divide, Customize
home.AddStampRequest.title=Add Stamp to PDF home.AddStampRequest.title=Add Stamp to PDF
home.AddStampRequest.desc=Add text or add image stamps at set locations home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize,Customise AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
home.PDFToBook.title=PDF to Book home.PDFToBook.title=PDF to Book
@@ -512,27 +512,23 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Advanced Colour options replace-color.title=Advanced Colour options
replace-color.header=Replace-Invert Colour PDF replace-color.header=Replace-Invert Color PDF
home.replaceColorPdf.title=Advanced Colour options home.replaceColorPdf.title=Advanced Colour options
home.replaceColorPdf.desc=Replace colour for text and background in PDF and invert full colour of pdf to reduce file size home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size
replaceColorPdf.tags=Replace Colour,Page operations,Back end,server side replaceColorPdf.tags=Replace Color,Page operations,Back end,server side
replace-color.selectText.1=Replace or Invert colour Options replace-color.selectText.1=Replace or Invert color Options
replace-color.selectText.2=Default(Default high contrast colours) replace-color.selectText.2=Default(Default high contrast colors)
replace-color.selectText.3=Custom(Customised colours) replace-color.selectText.3=Custom(Customized colors)
replace-color.selectText.4=Full-Invert(Invert all colours) replace-color.selectText.4=Full-Invert(Invert all colors)
replace-color.selectText.5=High contrast colour options replace-color.selectText.5=High contrast color options
replace-color.selectText.6=white text on black background replace-color.selectText.6=white text on black background
replace-color.selectText.7=Black text on white background replace-color.selectText.7=Black text on white background
replace-color.selectText.8=Yellow text on black background replace-color.selectText.8=Yellow text on black background
replace-color.selectText.9=Green text on black background replace-color.selectText.9=Green text on black background
replace-color.selectText.10=Choose text Colour replace-color.selectText.10=Choose text Color
replace-color.selectText.11=Choose background Colour replace-color.selectText.11=Choose background Color
replace-color.submit=Replace replace-color.submit=Replace
@@ -655,7 +651,7 @@ AddStampRequest.position=Position
AddStampRequest.overrideX=Override X Coordinate AddStampRequest.overrideX=Override X Coordinate
AddStampRequest.overrideY=Override Y Coordinate AddStampRequest.overrideY=Override Y Coordinate
AddStampRequest.customMargin=Custom Margin AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Colour AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit AddStampRequest.submit=Submit
@@ -787,8 +783,8 @@ removeAnnotations.submit=Remove
#compare #compare
compare.title=Compare compare.title=Compare
compare.header=Compare PDFs compare.header=Compare PDFs
compare.highlightColor.1=Highlight Colour 1: compare.highlightColor.1=Highlight Color 1:
compare.highlightColor.2=Highlight Colour 2: compare.highlightColor.2=Highlight Color 2:
compare.document.1=Document 1 compare.document.1=Document 1
compare.document.2=Document 2 compare.document.2=Document 2
compare.submit=Compare compare.submit=Compare
@@ -846,7 +842,7 @@ flatten.submit=Flatten
ScannerImageSplit.selectText.1=Angle Threshold: ScannerImageSplit.selectText.1=Angle Threshold:
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10). ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
ScannerImageSplit.selectText.3=Tolerance: ScannerImageSplit.selectText.3=Tolerance:
ScannerImageSplit.selectText.4=Determines the range of colour variation around the estimated background colour (default: 30). ScannerImageSplit.selectText.4=Determines the range of color variation around the estimated background color (default: 30).
ScannerImageSplit.selectText.5=Minimum Area: ScannerImageSplit.selectText.5=Minimum Area:
ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000). ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000).
ScannerImageSplit.selectText.7=Minimum Contour Area: ScannerImageSplit.selectText.7=Minimum Contour Area:
@@ -898,7 +894,7 @@ compress.title=Compress
compress.header=Compress PDF compress.header=Compress PDF
compress.credit=This service uses qpdf for PDF Compress/Optimisation. compress.credit=This service uses qpdf for PDF Compress/Optimisation.
compress.selectText.1=Manual Mode - From 1 to 4 compress.selectText.1=Manual Mode - From 1 to 4
compress.selectText.2=Optimisation level: compress.selectText.2=Optimization level:
compress.selectText.3=4 (Terrible for text images) compress.selectText.3=4 (Terrible for text images)
compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size
compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB) compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Encrypt
#watermark #watermark
watermark.title=Add Watermark watermark.title=Add Watermark
watermark.header=Add Watermark watermark.header=Add Watermark
watermark.customColor=Custom Text Colour
watermark.selectText.1=Select PDF to add watermark to: watermark.selectText.1=Select PDF to add watermark to:
watermark.selectText.2=Watermark Text: watermark.selectText.2=Watermark Text:
watermark.selectText.3=Font Size: watermark.selectText.3=Font Size:
watermark.selectText.4=Rotation (0-360): watermark.selectText.4=Rotation (0-360):
watermark.selectText.5=Width Spacer (Space between each watermark horizontally): watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
watermark.selectText.6=Height Spacer (Space between each watermark vertically): watermark.selectText.6=heightSpacer (Space between each watermark vertically):
watermark.selectText.7=Opacity (0% - 100%): watermark.selectText.7=Opacity (0% - 100%):
watermark.selectText.8=Watermark Type: watermark.selectText.8=Watermark Type:
watermark.selectText.9=Watermark Image: watermark.selectText.9=Watermark Image:
@@ -1268,11 +1261,6 @@ splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes #release notes
releases.footer=Releases releases.footer=Releases
@@ -1280,38 +1268,3 @@ releases.title=Release Notes
releases.header=Release Notes releases.header=Release Notes
releases.current.version=Current Release releases.current.version=Current Release
releases.note=Release notes are only available in English releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Encrypt
#watermark #watermark
watermark.title=Add Watermark watermark.title=Add Watermark
watermark.header=Add Watermark watermark.header=Add Watermark
watermark.customColor=Custom Text Color
watermark.selectText.1=Select PDF to add watermark to: watermark.selectText.1=Select PDF to add watermark to:
watermark.selectText.2=Watermark Text: watermark.selectText.2=Watermark Text:
watermark.selectText.3=Font Size: watermark.selectText.3=Font Size:
watermark.selectText.4=Rotation (0-360): watermark.selectText.4=Rotation (0-360):
watermark.selectText.5=Width Spacer (Space between each watermark horizontally): watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
watermark.selectText.6=Height Spacer (Space between each watermark vertically): watermark.selectText.6=heightSpacer (Space between each watermark vertically):
watermark.selectText.7=Opacity (0% - 100%): watermark.selectText.7=Opacity (0% - 100%):
watermark.selectText.8=Watermark Type: watermark.selectText.8=Watermark Type:
watermark.selectText.9=Watermark Image: watermark.selectText.9=Watermark Image:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Dividir PDF por capítulos
home.splitPdfByChapters.desc=Divida un PDF en varios archivos según su estructura de capítulos. home.splitPdfByChapters.desc=Divida un PDF en varios archivos según su estructura de capítulos.
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Reemplazar-Invertir-Color replace-color.title=Reemplazar-Invertir-Color
replace-color.header=Reemplazar-Invertir Color en PDF replace-color.header=Reemplazar-Invertir Color en PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Encriptar
#watermark #watermark
watermark.title=Añadir marca de agua watermark.title=Añadir marca de agua
watermark.header=Añadir marca de agua watermark.header=Añadir marca de agua
watermark.customColor=Personalizar color de texto
watermark.selectText.1=Seleccionar PDF para añadir marca de agua: watermark.selectText.1=Seleccionar PDF para añadir marca de agua:
watermark.selectText.2=Texto de la marca de agua: watermark.selectText.2=Texto de la marca de agua:
watermark.selectText.3=Tamaño de la Fuente: watermark.selectText.3=Tamaño de la Fuente:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Nivel de Marcador: Elige el nivel de marcadores para divi
splitByChapters.desc.3=Incluir Metadatos: Si está seleccionado, los metadatos del PDF original se incluirán en cada PDF dividido. splitByChapters.desc.3=Incluir Metadatos: Si está seleccionado, los metadatos del PDF original se incluirán en cada PDF dividido.
splitByChapters.desc.4=Permitir Duplicados: Si está seleccionado, permite que múltiples marcadores en la misma página creen archivos PDF separados. splitByChapters.desc.4=Permitir Duplicados: Si está seleccionado, permite que múltiples marcadores en la misma página creen archivos PDF separados.
splitByChapters.submit=Dividir PDF splitByChapters.submit=Dividir PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Enkriptatu
#watermark #watermark
watermark.title=Gehitu ur-marka watermark.title=Gehitu ur-marka
watermark.header=Gehitu ur-marka watermark.header=Gehitu ur-marka
watermark.customColor=Custom Text Color
watermark.selectText.1=Hautatu PDFa ur-marka gehitzeko: watermark.selectText.1=Hautatu PDFa ur-marka gehitzeko:
watermark.selectText.2=Ur-markaren testua: watermark.selectText.2=Ur-markaren testua:
watermark.selectText.3=Letra-tipoaren tamaina: watermark.selectText.3=Letra-tipoaren tamaina:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

File diff suppressed because it is too large Load Diff

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Séparer un PDF par chapitres
home.splitPdfByChapters.desc=Séparez un PDF en fichiers multiples en fonction de sa structure par chapitres. home.splitPdfByChapters.desc=Séparez un PDF en fichiers multiples en fonction de sa structure par chapitres.
splitPdfByChapters.tags=séparer,chapitres,split,chapters,bookmarks,organize splitPdfByChapters.tags=séparer,chapitres,split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Remplacer-Inverser-Couleur replace-color.title=Remplacer-Inverser-Couleur
replace-color.header=Remplacer-Inverser Couleur PDF replace-color.header=Remplacer-Inverser Couleur PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Déplacer vers la gauche
multiTool.moveRight=Déplacer vers la droite multiTool.moveRight=Déplacer vers la droite
multiTool.delete=Supprimer multiTool.delete=Supprimer
multiTool.dragDropMessage=Page(s) sélectionnées multiTool.dragDropMessage=Page(s) sélectionnées
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=Cette fonctionnalité est aussi disponible dans la <a href="{0}">page de l'outil multifonction</a>. Allez-y pour une interface page par page améliorée et des fonctionnalités additionnelles ! multiTool-advert.message=Cette fonctionnalité est aussi disponible dans la <a href="{0}">page de l'outil multifonction</a>. Allez-y pour une interface page par page améliorée et des fonctionnalités additionnelles !
@@ -1056,13 +1050,12 @@ addPassword.submit=Chiffrer
#watermark #watermark
watermark.title=Ajouter un filigrane watermark.title=Ajouter un filigrane
watermark.header=Ajouter un filigrane watermark.header=Ajouter un filigrane
watermark.customColor=Couleur de texte personnalisée
watermark.selectText.1=PDF auquel ajouter un filigrane watermark.selectText.1=PDF auquel ajouter un filigrane
watermark.selectText.2=Texte du filigrane watermark.selectText.2=Texte du filigrane
watermark.selectText.3=Taille de police watermark.selectText.3=Taille de police
watermark.selectText.4=Rotation (de 0 à 360 degrés) watermark.selectText.4=Rotation (de 0 à 360 degrés)
watermark.selectText.5=Width Spacer (espace entre chaque filigrane horizontalement) watermark.selectText.5=widthSpacer (espace entre chaque filigrane horizontalement)
watermark.selectText.6=Height Spacer (espace entre chaque filigrane verticalement) watermark.selectText.6=heightSpacer (espace entre chaque filigrane verticalement)
watermark.selectText.7=Opacité (de 0% à 100%) watermark.selectText.7=Opacité (de 0% à 100%)
watermark.selectText.8=Type de filigrane watermark.selectText.8=Type de filigrane
watermark.selectText.9=Image du filigrane watermark.selectText.9=Image du filigrane
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Niveau de Signet : Choisissez le niveau de signets à uti
splitByChapters.desc.3=Inclure les Métadonnées : Si coché, les métadonnées du PDF original seront incluses dans chaque PDF divisé. splitByChapters.desc.3=Inclure les Métadonnées : Si coché, les métadonnées du PDF original seront incluses dans chaque PDF divisé.
splitByChapters.desc.4=Autoriser les Doublons : Si coché, permet à plusieurs signets sur la même page de créer des PDF séparés. splitByChapters.desc.4=Autoriser les Doublons : Si coché, permet à plusieurs signets sur la même page de créer des PDF séparés.
splitByChapters.submit=Diviser le PDF splitByChapters.submit=Diviser le PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,12 +1050,11 @@ addPassword.submit=Criptigh
#watermark #watermark
watermark.title=Cuir Uisce leis watermark.title=Cuir Uisce leis
watermark.header=Cuir Uisce leis watermark.header=Cuir Uisce leis
watermark.customColor=Dath Téacs Saincheaptha
watermark.selectText.1=Roghnaigh PDF chun comhartha uisce a chur leis: watermark.selectText.1=Roghnaigh PDF chun comhartha uisce a chur leis:
watermark.selectText.2=Téacs Comhartha Uisce: watermark.selectText.2=Téacs Comhartha Uisce:
watermark.selectText.3=Méid cló: watermark.selectText.3=Méid cló:
watermark.selectText.4=Rothlú (0-360): watermark.selectText.4=Rothlú (0-360):
watermark.selectText.5=Width Spacer (Spás idir gach comhartha uisce go cothrománach): watermark.selectText.5=widthSpacer (Spás idir gach comhartha uisce go cothrománach):
watermark.selectText.6=spásaire airde (Spás idir gach comhartha uisce go hingearach): watermark.selectText.6=spásaire airde (Spás idir gach comhartha uisce go hingearach):
watermark.selectText.7=Teimhneacht (0% - 100%): watermark.selectText.7=Teimhneacht (0% - 100%):
watermark.selectText.8=Cineál Comhartha Uisce: watermark.selectText.8=Cineál Comhartha Uisce:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=अध्यायों पर अलग-कर
home.splitPdfByChapters.desc=पुस्तक के अध्याय की संरचना पर आधारित एक PDF को बहिन-भागों में विभाजित करें home.splitPdfByChapters.desc=पुस्तक के अध्याय की संरचना पर आधारित एक PDF को बहिन-भागों में विभाजित करें
splitPdfByChapters.tags=विभाजन,अध्याय,पसंदीदा,रजैत splitPdfByChapters.tags=विभाजन,अध्याय,पसंदीदा,रजैत
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=चित्र रंग परिवर्तन/उलटकर परिवर्तन PDF replace-color.header=चित्र रंग परिवर्तन/उलटकर परिवर्तन PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=एन्क्रिप्ट करें
#watermark #watermark
watermark.title=वॉटरमार्क जोड़ें watermark.title=वॉटरमार्क जोड़ें
watermark.header=वॉटरमार्क जोड़ें watermark.header=वॉटरमार्क जोड़ें
watermark.customColor=संवैधित टेक्स्ट रंग
watermark.selectText.1=वॉटरमार्क जोड़ने के लिए पीडीएफ चुनें: watermark.selectText.1=वॉटरमार्क जोड़ने के लिए पीडीएफ चुनें:
watermark.selectText.2=वॉटरमार्क टेक्स्ट: watermark.selectText.2=वॉटरमार्क टेक्स्ट:
watermark.selectText.3=फ़ॉन्ट साइज़: watermark.selectText.3=फ़ॉन्ट साइज़:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=लेमैक्स स्तर: विभाजन
splitByChapters.desc.3=मॉडेटरेट का शामिल करें: यदि सत्यापित किया जाता है, प्रारंभिक PDF की मॉडेटरेट को प्रत्येक विभाग PDF में शामिल किया जाएगा। splitByChapters.desc.3=मॉडेटरेट का शामिल करें: यदि सत्यापित किया जाता है, प्रारंभिक PDF की मॉडेटरेट को प्रत्येक विभाग PDF में शामिल किया जाएगा।
splitByChapters.desc.4=यादृच्छिक पुनरावृत्ति अनुमोदित: यदि सत्यापित किया जाता है, एक ही पेज पर दोहरे मूल्यांकन पब्लिक पीड़एफ बनाने की संभावना देता है। splitByChapters.desc.4=यादृच्छिक पुनरावृत्ति अनुमोदित: यदि सत्यापित किया जाता है, एक ही पेज पर दोहरे मूल्यांकन पब्लिक पीड़एफ बनाने की संभावना देता है।
splitByChapters.submit=PDF विभाजित splitByChapters.submit=PDF विभाजित
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Podijeli PDF prema glavama
home.splitPdfByChapters.desc=Podijeli PDF na više datoteka prema njegovom strukturnom obliku glava. home.splitPdfByChapters.desc=Podijeli PDF na više datoteka prema njegovom strukturnom obliku glava.
splitPdfByChapters.tags=podjela, glave, markere, organizacija splitPdfByChapters.tags=podjela, glave, markere, organizacija
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Zameni-inverziranje boja u PDF-u replace-color.header=Zameni-inverziranje boja u PDF-u
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Šifriraj
#watermark #watermark
watermark.title=Dodaj vodeni žig watermark.title=Dodaj vodeni žig
watermark.header=Dodaj vodeni žig watermark.header=Dodaj vodeni žig
watermark.customColor=Prilagođena boja teksta
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga: watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
watermark.selectText.2=Tekst vodenog žiga: watermark.selectText.2=Tekst vodenog žiga:
watermark.selectText.3=Veličina fonta: watermark.selectText.3=Veličina fonta:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Nivo oznaka: Odaberite nivo oznaka koji će se koristiti
splitByChapters.desc.3=Uključi metapodatke: Ako je pokušano, metapodaci iz originalne PDF datoteke će biti uključeni u svaku podijeljenu PDF datoteku. splitByChapters.desc.3=Uključi metapodatke: Ako je pokušano, metapodaci iz originalne PDF datoteke će biti uključeni u svaku podijeljenu PDF datoteku.
splitByChapters.desc.4=Dopuštaj duplikate: Ako je ova opcija zaštićena, dozvoljava se da se na istoj strani mogu stvoriti posebne PDF datoteke s više oznaka. splitByChapters.desc.4=Dopuštaj duplikate: Ako je ova opcija zaštićena, dozvoljava se da se na istoj strani mogu stvoriti posebne PDF datoteke s više oznaka.
splitByChapters.submit=Podijeli PDF splitByChapters.submit=Podijeli PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=PDF felosztása fejezetek szerint
home.splitPdfByChapters.desc=Fejezetei alapján egy PDF fájl több dokumentumba osztás. home.splitPdfByChapters.desc=Fejezetei alapján egy PDF fájl több dokumentumba osztás.
splitPdfByChapters.tags=Osztás, fejezetek, jelezes, organizálás splitPdfByChapters.tags=Osztás, fejezetek, jelezes, organizálás
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Visszaalakítás-összevétel a színekkel PDF-ben replace-color.header=Visszaalakítás-összevétel a színekkel PDF-ben
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Titkosítás
#watermark #watermark
watermark.title=Vízjel hozzáadása watermark.title=Vízjel hozzáadása
watermark.header=Vízjel hozzáadása watermark.header=Vízjel hozzáadása
watermark.customColor=Egyéni szövegszín
watermark.selectText.1=Válassza ki a PDF-t, amelyhez vízjelet kíván hozzáadni: watermark.selectText.1=Válassza ki a PDF-t, amelyhez vízjelet kíván hozzáadni:
watermark.selectText.2=Vízjel szövege: watermark.selectText.2=Vízjel szövege:
watermark.selectText.3=Betűméret: watermark.selectText.3=Betűméret:
watermark.selectText.4=Forgatás (0-360): watermark.selectText.4=Forgatás (0-360):
watermark.selectText.5=Width Spacer (Hely a vízjelek között vízszintesen): watermark.selectText.5=widthSpacer (Hely a vízjelek között vízszintesen):
watermark.selectText.6=Height Spacer (Hely a vízjelek között függőlegesen): watermark.selectText.6=heightSpacer (Hely a vízjelek között függőlegesen):
watermark.selectText.7=Átlátszóság (0% - 100%): watermark.selectText.7=Átlátszóság (0% - 100%):
watermark.selectText.8=Vízjel típusa: watermark.selectText.8=Vízjel típusa:
watermark.selectText.9=Vízjel képe: watermark.selectText.9=Vízjel képe:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Metaadatok belefoglalása: Ha bevanítva van, az eredeti PDF fájl metaadatai megtartódnak minden osztott fájlban. splitByChapters.desc.3=Metaadatok belefoglalása: Ha bevanítva van, az eredeti PDF fájl metaadatai megtartódnak minden osztott fájlban.
splitByChapters.desc.4=Duplikációk engedélyezése: Ha bevanítva van, lehetővé teszi a megadott oldalon lévő több kijelzőszint alapján új PDF-ek létrehozása. splitByChapters.desc.4=Duplikációk engedélyezése: Ha bevanítva van, lehetővé teszi a megadott oldalon lévő több kijelzőszint alapján új PDF-ek létrehozása.
splitByChapters.submit=PDF osztás splitByChapters.submit=PDF osztás
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Pisahkan PDF berdasarkan Bab
home.splitPdfByChapters.desc=Memisahkan PDF menjadi beberapa file berdasarkan struktur babnya. home.splitPdfByChapters.desc=Memisahkan PDF menjadi beberapa file berdasarkan struktur babnya.
splitPdfByChapters.tags=pemisahan,bab,bookmark,atur splitPdfByChapters.tags=pemisahan,bab,bookmark,atur
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Ganti-Inversi-Warna replace-color.title=Ganti-Inversi-Warna
replace-color.header=Ganti-Inversi Warna PDF replace-color.header=Ganti-Inversi Warna PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Enkripsi
#watermark #watermark
watermark.title=Tambahkan Watermark watermark.title=Tambahkan Watermark
watermark.header=Tambahkan Watermark watermark.header=Tambahkan Watermark
watermark.customColor=Warna Teks Kustom
watermark.selectText.1=Pilih PDF untuk menambahkan watermark: watermark.selectText.1=Pilih PDF untuk menambahkan watermark:
watermark.selectText.2=Text Watermark: watermark.selectText.2=Text Watermark:
watermark.selectText.3=Ukuran Huruf: watermark.selectText.3=Ukuran Huruf:
watermark.selectText.4=Rotasi (0-360): watermark.selectText.4=Rotasi (0-360):
watermark.selectText.5=Width Spacer (Spasi diantara setiap watermark horisontal): watermark.selectText.5=widthSpacer (Spasi diantara setiap watermark horisontal):
watermark.selectText.6=Height Spacer (Spasi diantara setiap watermark vertikal): watermark.selectText.6=heightSpacer (Spasi diantara setiap watermark vertikal):
watermark.selectText.7=Kejernihan (0% - 100%): watermark.selectText.7=Kejernihan (0% - 100%):
watermark.selectText.8=Tipe Watermark: watermark.selectText.8=Tipe Watermark:
watermark.selectText.9=Gambar Watermark: watermark.selectText.9=Gambar Watermark:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Tingkatan Markah: Pilih tingkatan markah yang digunakan u
splitByChapters.desc.3=Termasuk Metadata: Jika dicentang, metadata asli PDF akan disertakan dalam setiap PDF yang dibagi. splitByChapters.desc.3=Termasuk Metadata: Jika dicentang, metadata asli PDF akan disertakan dalam setiap PDF yang dibagi.
splitByChapters.desc.4=Izinkan Duplikat: Jika dicentang, mengizinkan beberapa markah pada halaman yang sama untuk membuat PDF terpisah. splitByChapters.desc.4=Izinkan Duplikat: Jika dicentang, mengizinkan beberapa markah pada halaman yang sama untuk membuat PDF terpisah.
splitByChapters.submit=Pecah PDF splitByChapters.submit=Pecah PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Dividi PDF per capitoli
home.splitPdfByChapters.desc=Dividi un PDF in più file in base alla struttura dei capitoli. home.splitPdfByChapters.desc=Dividi un PDF in più file in base alla struttura dei capitoli.
splitPdfByChapters.tags=dividi, capitoli, segnalibri, organizza splitPdfByChapters.tags=dividi, capitoli, segnalibri, organizza
home.validateSignature.title=Convalida la firma PDF
home.validateSignature.desc=Verificare le firme digitali e i certificati nei documenti PDF
validateSignature.tags=firma,verifica,convalida,pdf,certificato,firma digitale,convalida firma,convalida certificato
#replace-invert-color #replace-invert-color
replace-color.title=Sostituisci-Inverti-Colore replace-color.title=Sostituisci-Inverti-Colore
replace-color.header=Sostituisci-Inverti colore PDF replace-color.header=Sostituisci-Inverti colore PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Sposta a sinistra
multiTool.moveRight=Sposta a destra multiTool.moveRight=Sposta a destra
multiTool.delete=Elimina multiTool.delete=Elimina
multiTool.dragDropMessage=Pagina(e) selezionata(e) multiTool.dragDropMessage=Pagina(e) selezionata(e)
multiTool.undo=Annulla
multiTool.redo=Rifai
#multiTool-advert #multiTool-advert
multiTool-advert.message=Questa funzione è disponibile anche nella nostra <a href="{0}">pagina multi-strumento</a>. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive! multiTool-advert.message=Questa funzione è disponibile anche nella nostra <a href="{0}">pagina multi-strumento</a>. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive!
@@ -1056,7 +1050,6 @@ addPassword.submit=Crittografa
#watermark #watermark
watermark.title=Aggiungi Filigrana watermark.title=Aggiungi Filigrana
watermark.header=Aggiungi filigrana watermark.header=Aggiungi filigrana
watermark.customColor=Colore testo personalizzato
watermark.selectText.1=Seleziona PDF a cui aggiungere la filigrana: watermark.selectText.1=Seleziona PDF a cui aggiungere la filigrana:
watermark.selectText.2=Testo: watermark.selectText.2=Testo:
watermark.selectText.3=Dimensione carattere: watermark.selectText.3=Dimensione carattere:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Livello segnalibro: seleziona il livello dei segnalibri d
splitByChapters.desc.3=Includi metadati: se selezionato, i metadati del PDF originale verranno inclusi in ogni PDF diviso. splitByChapters.desc.3=Includi metadati: se selezionato, i metadati del PDF originale verranno inclusi in ogni PDF diviso.
splitByChapters.desc.4=Consenti duplicati: se selezionata, consente più segnalibri sulla stessa pagina per creare PDF separati. splitByChapters.desc.4=Consenti duplicati: se selezionata, consente più segnalibri sulla stessa pagina per creare PDF separati.
splitByChapters.submit=Dividi PDF splitByChapters.submit=Dividi PDF
#File Chooser
fileChooser.click=Clicca
fileChooser.or=o
fileChooser.dragAndDrop=Trascina & Rilascia
fileChooser.hoveredDragAndDrop=Trascina & rilascia i file qui
#release notes
releases.footer=Rilasci
releases.title=Note di rilascio
releases.header=Note di rilascio
releases.current.version=Rilascio corrente
releases.note=Le note di rilascio sono disponibili solo in inglese
#Validate Signature
validateSignature.title=Validare le firme PDF
validateSignature.header=Convalidare le firme digitali
validateSignature.selectPDF=Seleziona il file PDF firmato
validateSignature.submit=Convalida firme
validateSignature.results=Risultati di convalida
validateSignature.status=Stato
validateSignature.signer=Firmatario
validateSignature.date=Data
validateSignature.reason=Ragione
validateSignature.location=Posizione
validateSignature.noSignatures=Nessuna firma digitale trovata in questo documento
validateSignature.status.valid=Valida
validateSignature.status.invalid=Invalida
validateSignature.chain.invalid=Convalida della catena di certificati non riuscita: impossibile verificare l'identità del firmatario
validateSignature.trust.invalid=Certificato non presente nell'archivio attendibile: la fonte non può essere verificata
validateSignature.cert.expired=Il certificato è scaduto
validateSignature.cert.revoked=Il certificato è stato revocato
validateSignature.signature.info=Informazioni sulla firma
validateSignature.signature=Firma
validateSignature.signature.mathValid=La firma è matematicamente valida MA:
validateSignature.selectCustomCert=File di certificato personalizzato X.509 (opzionale)
validateSignature.cert.info=Dettagli del certificato
validateSignature.cert.issuer=Emittente
validateSignature.cert.subject=Soggetto
validateSignature.cert.serialNumber=Numero di serie
validateSignature.cert.validFrom=Valido da
validateSignature.cert.validUntil=Valido fino a
validateSignature.cert.algorithm=Algoritmo
validateSignature.cert.keySize=Dimensione chiave
validateSignature.cert.version=Versione
validateSignature.cert.keyUsage=Utilizzo della chiave
validateSignature.cert.selfSigned=Autofirmato
validateSignature.cert.bits=bit

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=暗号化
#watermark #watermark
watermark.title=透かしの追加 watermark.title=透かしの追加
watermark.header=透かしの追加 watermark.header=透かしの追加
watermark.customColor=文字色のカスタム
watermark.selectText.1=透かしを追加するPDFを選択: watermark.selectText.1=透かしを追加するPDFを選択:
watermark.selectText.2=透かしのテキスト: watermark.selectText.2=透かしのテキスト:
watermark.selectText.3=文字サイズ: watermark.selectText.3=文字サイズ:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=챕터별로 PDF 분할
home.splitPdfByChapters.desc=PDF를 여러 파일로 나눕니다. 각 장의 구조에 따라. home.splitPdfByChapters.desc=PDF를 여러 파일로 나눕니다. 각 장의 구조에 따라.
splitPdfByChapters.tags=분할, 챕터, 북마크, 조직화 splitPdfByChapters.tags=분할, 챕터, 북마크, 조직화
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=색상 교체/반전 PDF replace-color.header=색상 교체/반전 PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=암호화
#watermark #watermark
watermark.title=워터마크 추가 watermark.title=워터마크 추가
watermark.header=워터마크 추가 watermark.header=워터마크 추가
watermark.customColor=사용자 정의 텍스트 색상
watermark.selectText.1=워터마크를 추가할 PDF 선택: watermark.selectText.1=워터마크를 추가할 PDF 선택:
watermark.selectText.2=워터마크 텍스트: watermark.selectText.2=워터마크 텍스트:
watermark.selectText.3=폰트 크기: watermark.selectText.3=폰트 크기:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=북마크 레벨: 분할에 사용할 북마크 레벨을
splitByChapters.desc.3=메타데이터 포함: 체크하면 각 분할된 PDF에는 원본 PDF의 메타데이터가 포함됩니다. splitByChapters.desc.3=메타데이터 포함: 체크하면 각 분할된 PDF에는 원본 PDF의 메타데이터가 포함됩니다.
splitByChapters.desc.4=중복 허용: 중복 북마크가 있는 같은 페이지에 여러 번 분할 PDF를 생성합니다. splitByChapters.desc.4=중복 허용: 중복 북마크가 있는 같은 페이지에 여러 번 분할 PDF를 생성합니다.
splitByChapters.submit=PDF 분할 splitByChapters.submit=PDF 분할
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=PDF op hoofdstukken splitsen
home.splitPdfByChapters.desc=Splits een PDF op basis van zijn hoofdstukstructuur in meerdere bestanden. home.splitPdfByChapters.desc=Splits een PDF op basis van zijn hoofdstukstructuur in meerdere bestanden.
splitPdfByChapters.tags=splitsen, hoofdstukken, bookmarks, organiseren splitPdfByChapters.tags=splitsen, hoofdstukken, bookmarks, organiseren
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Kleur-instellingen voor PDF's replace-color.header=Kleur-instellingen voor PDF's
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Versleutelen
#watermark #watermark
watermark.title=Watermerk toevoegen watermark.title=Watermerk toevoegen
watermark.header=Watermerk toevoegen watermark.header=Watermerk toevoegen
watermark.customColor=Aangepaste tekstkleur
watermark.selectText.1=Selecteer PDF om watermerk toe te voegen: watermark.selectText.1=Selecteer PDF om watermerk toe te voegen:
watermark.selectText.2=Watermerk tekst: watermark.selectText.2=Watermerk tekst:
watermark.selectText.3=Tekengrootte: watermark.selectText.3=Tekengrootte:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Boekmarkeer niveau: Kies het boekmarkeer niveau om te geb
splitByChapters.desc.3=Metadata inclusief: Als gecijfeld, de originele PDF's metadata wordt ingevoegd in elk gesplitst PDF-bestand. splitByChapters.desc.3=Metadata inclusief: Als gecijfeld, de originele PDF's metadata wordt ingevoegd in elk gesplitst PDF-bestand.
splitByChapters.desc.4=Dubbele items toestaan: Als gecijfeld, zorgen multiple boekmarkeersymboolen op dezelfde pagina voor het maken van aparte PDF-bestanden. splitByChapters.desc.4=Dubbele items toestaan: Als gecijfeld, zorgen multiple boekmarkeersymboolen op dezelfde pagina voor het maken van aparte PDF-bestanden.
splitByChapters.submit=PDF splitsen splitByChapters.submit=PDF splitsen
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Krypter
#watermark #watermark
watermark.title=Legg til vannmerke watermark.title=Legg til vannmerke
watermark.header=Legg til vannmerke watermark.header=Legg til vannmerke
watermark.customColor=Tilpasset Tekstfarge
watermark.selectText.1=Velg PDF-fil å legge til vannmerke på: watermark.selectText.1=Velg PDF-fil å legge til vannmerke på:
watermark.selectText.2=Vannmerketekst: watermark.selectText.2=Vannmerketekst:
watermark.selectText.3=Skriftstørrelse: watermark.selectText.3=Skriftstørrelse:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

55
src/main/resources/messages_pl_PL.properties Normal file → Executable file
View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Podziel PDF według rozdziałów
home.splitPdfByChapters.desc=Podział pliku PDF na wiele plików na podstawie struktury rozdziałów. home.splitPdfByChapters.desc=Podział pliku PDF na wiele plików na podstawie struktury rozdziałów.
splitPdfByChapters.tags=podział, rozdziały, zakładki, porządkowanie, organizacja splitPdfByChapters.tags=podział, rozdziały, zakładki, porządkowanie, organizacja
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Zamień-Odwróć-Kolor replace-color.title=Zamień-Odwróć-Kolor
replace-color.header=Zamień-Odwróć kolor PDF replace-color.header=Zamień-Odwróć kolor PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Zablokuj
#watermark #watermark
watermark.title=Dodaj znak wodny watermark.title=Dodaj znak wodny
watermark.header=Dodaj znak wodny watermark.header=Dodaj znak wodny
watermark.customColor=Własny kolor tekstu
watermark.selectText.1=Wybierz dokument PDF, do którego chcesz dodać znak wodny: watermark.selectText.1=Wybierz dokument PDF, do którego chcesz dodać znak wodny:
watermark.selectText.2=Treść znaku wodnego: watermark.selectText.2=Treść znaku wodnego:
watermark.selectText.3=Rozmiar czcionki: watermark.selectText.3=Rozmiar czcionki:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Poziom Zakładek: Wybierz poziom zakładek, który ma zos
splitByChapters.desc.3=Dołącz Metadane: Jeśli opcja ta jest zaznaczona, metadane oryginalnego pliku PDF zostaną uwzględnione w każdym rozdzielonych plików PDF. splitByChapters.desc.3=Dołącz Metadane: Jeśli opcja ta jest zaznaczona, metadane oryginalnego pliku PDF zostaną uwzględnione w każdym rozdzielonych plików PDF.
splitByChapters.desc.4=Zezwól na Duplikaty: Jeśli ta opcja jest zaznaczona, pozwala na tworzenie oddzielnych plików PDF przez wiele zakładek na tej samej stronie. splitByChapters.desc.4=Zezwól na Duplikaty: Jeśli ta opcja jest zaznaczona, pozwala na tworzenie oddzielnych plików PDF przez wiele zakładek na tej samej stronie.
splitByChapters.submit=Podziel PDF splitByChapters.submit=Podziel PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Divide PDF por Capítulos
home.splitPdfByChapters.desc=Divide um PDF em vários arquivos baseado na sua estrutura de capítulos. home.splitPdfByChapters.desc=Divide um PDF em vários arquivos baseado na sua estrutura de capítulos.
splitPdfByChapters.tags=dividir,capítulos,favoritos,organizar splitPdfByChapters.tags=dividir,capítulos,favoritos,organizar
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Substituir-Inverter-Cor replace-color.title=Substituir-Inverter-Cor
replace-color.header=Substitui-Inverter Cor PDF replace-color.header=Substitui-Inverter Cor PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Criptografar
#watermark #watermark
watermark.title=Adicionar marca d'água watermark.title=Adicionar marca d'água
watermark.header=Adicionar marca d'água watermark.header=Adicionar marca d'água
watermark.customColor=Cor de texto personalizada
watermark.selectText.1=Selecione PDF para adicionar a marca d'água: watermark.selectText.1=Selecione PDF para adicionar a marca d'água:
watermark.selectText.2=Texto da marca d'água: watermark.selectText.2=Texto da marca d'água:
watermark.selectText.3=Tamanho da fonte: watermark.selectText.3=Tamanho da fonte:
watermark.selectText.4=Rotação (0-360): watermark.selectText.4=Rotação (0-360):
watermark.selectText.5=Width Spacer (Espaço entre cada marca d'água horizontalmente): watermark.selectText.5=widthSpacer (Espaço entre cada marca d'água horizontalmente):
watermark.selectText.6=Height Spacer (Espaço entre cada marca d'água verticalmente): watermark.selectText.6=heightSpacer (Espaço entre cada marca d'água verticalmente):
watermark.selectText.7=Opacidade (0% - 100%): watermark.selectText.7=Opacidade (0% - 100%):
watermark.selectText.8=Tipo de marca d'água: watermark.selectText.8=Tipo de marca d'água:
watermark.selectText.9=Imagem da marca d'água: watermark.selectText.9=Imagem da marca d'água:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Nível de Marcador: Escolha o nível de marcador a ser us
splitByChapters.desc.3=Incluir Metadados: Se marcado, os metadados do PDF original serão incluidos em cada divisão do PDF. splitByChapters.desc.3=Incluir Metadados: Se marcado, os metadados do PDF original serão incluidos em cada divisão do PDF.
splitByChapters.desc.4=Permitir Cópias: Se marcado, habilita vários marcadores na mesma página para criar PDFs separados. splitByChapters.desc.4=Permitir Cópias: Se marcado, habilita vários marcadores na mesma página para criar PDFs separados.
splitByChapters.submit=Dividir PDF splitByChapters.submit=Dividir PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Dividir PDF por Capítulos
home.splitPdfByChapters.desc=Divida um PDF em vários arquivos com base na estrutura dos capítulos. home.splitPdfByChapters.desc=Divida um PDF em vários arquivos com base na estrutura dos capítulos.
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Substituir-Inverter Cor do PDF replace-color.header=Substituir-Inverter Cor do PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Proteger
#watermark #watermark
watermark.title=Adicionar Marca d'Água watermark.title=Adicionar Marca d'Água
watermark.header=Adicionar Marca d'Água watermark.header=Adicionar Marca d'Água
watermark.customColor=Personalizar a cor do texto
watermark.selectText.1=Seleccione o PDF para Adicionar a Marca d'Água watermark.selectText.1=Seleccione o PDF para Adicionar a Marca d'Água
watermark.selectText.2=Texto da Marca d'Água watermark.selectText.2=Texto da Marca d'Água
watermark.selectText.3=Tamanho da Fonte watermark.selectText.3=Tamanho da Fonte
watermark.selectText.4=Rotação (0-360) watermark.selectText.4=Rotação (0-360)
watermark.selectText.5=Espaçamento Horizontal (Width Spacer) watermark.selectText.5=Espaçamento Horizontal (widthSpacer)
watermark.selectText.6=Espaçamento Vertical (Height Spacer) watermark.selectText.6=Espaçamento Vertical (heightSpacer)
watermark.selectText.7=Opacidade (0% - 100%) watermark.selectText.7=Opacidade (0% - 100%)
watermark.selectText.8=Tipo de Marca d'Água watermark.selectText.8=Tipo de Marca d'Água
watermark.selectText.9=Imagem da Marca d'Água watermark.selectText.9=Imagem da Marca d'Água
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Nível de Anotações: Escolha o nível das anotações a
splitByChapters.desc.3=Inclua Metadados: Se marcado, os metadados originais do PDF serão incluídos em cada PDF dividido. splitByChapters.desc.3=Inclua Metadados: Se marcado, os metadados originais do PDF serão incluídos em cada PDF dividido.
splitByChapters.desc.4=Permitir Duplicatas: Se marcado, permite a criação de vários bookmarks na mesma página para criar separadamente vários PDFs. splitByChapters.desc.4=Permitir Duplicatas: Se marcado, permite a criação de vários bookmarks na mesma página para criar separadamente vários PDFs.
splitByChapters.submit=Dividir o PDF splitByChapters.submit=Dividir o PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Criptează
#watermark #watermark
watermark.title=Adaugă Filigran watermark.title=Adaugă Filigran
watermark.header=Adaugă Filigran watermark.header=Adaugă Filigran
watermark.customColor=Culoare Text Personalizată
watermark.selectText.1=Selectează PDF-ul la care să adaugi filigranul: watermark.selectText.1=Selectează PDF-ul la care să adaugi filigranul:
watermark.selectText.2=Textul Filigranului: watermark.selectText.2=Textul Filigranului:
watermark.selectText.3=Mărimea fontului: watermark.selectText.3=Mărimea fontului:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Разделить PDF по разделам
home.splitPdfByChapters.desc=Разделите PDF на несколько файлов на основе структуры его разделов home.splitPdfByChapters.desc=Разделите PDF на несколько файлов на основе структуры его разделов
splitPdfByChapters.tags=разделение, разделы, закладки, организация splitPdfByChapters.tags=разделение, разделы, закладки, организация
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Заменить-Обратное изменение цвета PDF replace-color.header=Заменить-Обратное изменение цвета PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Шифровать
#watermark #watermark
watermark.title=Добавить водяной знак watermark.title=Добавить водяной знак
watermark.header=Добавить водяной знак watermark.header=Добавить водяной знак
watermark.customColor=Настроенный цвет текста
watermark.selectText.1=Выберите PDF, чтобы добавить водяной знак: watermark.selectText.1=Выберите PDF, чтобы добавить водяной знак:
watermark.selectText.2=Текст водяного знака: watermark.selectText.2=Текст водяного знака:
watermark.selectText.3=Размер шрифта: watermark.selectText.3=Размер шрифта:
watermark.selectText.4=Поворот (0-360): watermark.selectText.4=Поворот (0-360):
watermark.selectText.5=Width Spacer (пробел между каждым водяным знаком по горизонтали): watermark.selectText.5=widthSpacer (пробел между каждым водяным знаком по горизонтали):
watermark.selectText.6=Height Spacer (пробел между каждым водяным знаком по вертикали): watermark.selectText.6=heightSpacer (пробел между каждым водяным знаком по вертикали):
watermark.selectText.7=Непрозрачность (0% - 100%): watermark.selectText.7=Непрозрачность (0% - 100%):
watermark.selectText.8=Тип водяного знака: watermark.selectText.8=Тип водяного знака:
watermark.selectText.9=Изображение водяного знака: watermark.selectText.9=Изображение водяного знака:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Уровень закладки: выберите уро
splitByChapters.desc.3=Включить метаданные: если эта опция отмечена, метаданные исходного PDF будут включены в каждый разбитый PDF. splitByChapters.desc.3=Включить метаданные: если эта опция отмечена, метаданные исходного PDF будут включены в каждый разбитый PDF.
splitByChapters.desc.4=Позволять дубликаты: если эта опция отмечена, на одной странице могут быть созданы несколько PDF из-за нескольких одинаковых закладок. splitByChapters.desc.4=Позволять дубликаты: если эта опция отмечена, на одной странице могут быть созданы несколько PDF из-за нескольких одинаковых закладок.
splitByChapters.submit=Разделить PDF splitByChapters.submit=Разделить PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Zašifrovať
#watermark #watermark
watermark.title=Pridať vodotlač watermark.title=Pridať vodotlač
watermark.header=Pridať vodotlač watermark.header=Pridať vodotlač
watermark.customColor=Vlastná farba textu
watermark.selectText.1=Vyberte PDF, do ktorého chcete pridať vodotlač: watermark.selectText.1=Vyberte PDF, do ktorého chcete pridať vodotlač:
watermark.selectText.2=Text vodotlače: watermark.selectText.2=Text vodotlače:
watermark.selectText.3=Veľkosť písma: watermark.selectText.3=Veľkosť písma:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Enkriptuj
#watermark #watermark
watermark.title=Dodaj vodeni žig watermark.title=Dodaj vodeni žig
watermark.header=Dodaj vodeni žig watermark.header=Dodaj vodeni žig
watermark.customColor=Custom Text Color
watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga: watermark.selectText.1=Izaberite PDF za dodavanje vodenog žiga:
watermark.selectText.2=Tekst vodenog žiga: watermark.selectText.2=Tekst vodenog žiga:
watermark.selectText.3=Veličina fonta: watermark.selectText.3=Veličina fonta:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Dela upp PDF efter kapitel
home.splitPdfByChapters.desc=Dela upp en PDF till flera filer baserat på dess kapitelstruktur. home.splitPdfByChapters.desc=Dela upp en PDF till flera filer baserat på dess kapitelstruktur.
splitPdfByChapters.tags=dela,kapitel,bokmärken,organisera splitPdfByChapters.tags=dela,kapitel,bokmärken,organisera
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Ersätt-Invertera färg på PDF replace-color.header=Ersätt-Invertera färg på PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Kryptera
#watermark #watermark
watermark.title=Lägg till vattenstämpel watermark.title=Lägg till vattenstämpel
watermark.header=Lägg till vattenstämpel watermark.header=Lägg till vattenstämpel
watermark.customColor=Anpassad textfärg
watermark.selectText.1=Välj PDF för att lägga till vattenstämpel till: watermark.selectText.1=Välj PDF för att lägga till vattenstämpel till:
watermark.selectText.2=Vattenmärkestext: watermark.selectText.2=Vattenmärkestext:
watermark.selectText.3=Teckenstorlek: watermark.selectText.3=Teckenstorlek:
watermark.selectText.4=Vändning (0-360): watermark.selectText.4=Vändning (0-360):
watermark.selectText.5=Width Spacer (mellanrum mellan varje vattenstämpel horisontellt): watermark.selectText.5=widthSpacer (mellanrum mellan varje vattenstämpel horisontellt):
watermark.selectText.6=Height Spacer (mellanrum mellan varje vattenstämpel vertikalt): watermark.selectText.6=heightSpacer (mellanrum mellan varje vattenstämpel vertikalt):
watermark.selectText.7=Opacitet (0% - 100%): watermark.selectText.7=Opacitet (0% - 100%):
watermark.selectText.8=Vattenstämpeltyp: watermark.selectText.8=Vattenstämpeltyp:
watermark.selectText.9=Vattenstämpelbild: watermark.selectText.9=Vattenstämpelbild:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bokmärkesnivå: Välj nivån av bokmärken att använda
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Tillåt duplicieringar: Om kryssrutan är markerad tillåts flera bokmärken på samma sida skapa individuella PDF:er. splitByChapters.desc.4=Tillåt duplicieringar: Om kryssrutan är markerad tillåts flera bokmärken på samma sida skapa individuella PDF:er.
splitByChapters.submit=Dela upp PDF splitByChapters.submit=Dela upp PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=เข้ารหัส
#watermark #watermark
watermark.title=เพิ่มลายน้ำ watermark.title=เพิ่มลายน้ำ
watermark.header=เพิ่มลายน้ำ watermark.header=เพิ่มลายน้ำ
watermark.customColor=สีข้อความที่กำหนดเอง
watermark.selectText.1=เลือก PDF เพื่อเพิ่มลายน้ำ: watermark.selectText.1=เลือก PDF เพื่อเพิ่มลายน้ำ:
watermark.selectText.2=ข้อความลายน้ำ: watermark.selectText.2=ข้อความลายน้ำ:
watermark.selectText.3=ขนาดฟอนต์: watermark.selectText.3=ขนาดฟอนต์:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=ระดับบุคคลที่ได้รับ
splitByChapters.desc.3=รวมข้อมูลเสริม: หากถูกเลือก ข้อมูลเสริมของไฟล์ PDF ที่เดิมจะถูกรวมอยู่ในแต่ละไฟล์ที่แบ่งออก splitByChapters.desc.3=รวมข้อมูลเสริม: หากถูกเลือก ข้อมูลเสริมของไฟล์ PDF ที่เดิมจะถูกรวมอยู่ในแต่ละไฟล์ที่แบ่งออก
splitByChapters.desc.4=อนุญาตให้มีการซ้ำ: หากถูกเลือก จะทำให้สามารถสร้างไฟล์ PDF แยกออกมาจากหน้าเดียวกันได้หลายรายการ splitByChapters.desc.4=อนุญาตให้มีการซ้ำ: หากถูกเลือก จะทำให้สามารถสร้างไฟล์ PDF แยกออกมาจากหน้าเดียวกันได้หลายรายการ
splitByChapters.submit=แบ่งไฟล์ PDF splitByChapters.submit=แบ่งไฟล์ PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Şifrele
#watermark #watermark
watermark.title=Filigran Ekle watermark.title=Filigran Ekle
watermark.header=Filigran Ekle watermark.header=Filigran Ekle
watermark.customColor=Özel Metin Rengi
watermark.selectText.1=Filigran eklemek için PDF seçin: watermark.selectText.1=Filigran eklemek için PDF seçin:
watermark.selectText.2=Filigran Metni: watermark.selectText.2=Filigran Metni:
watermark.selectText.3=Yazı Boyutu: watermark.selectText.3=Yazı Boyutu:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=Шифрувати
#watermark #watermark
watermark.title=Додати водяний знак watermark.title=Додати водяний знак
watermark.header=Додати водяний знак watermark.header=Додати водяний знак
watermark.customColor=Користувацький колір тексту
watermark.selectText.1=Виберіть PDF, щоб додати водяний знак: watermark.selectText.1=Виберіть PDF, щоб додати водяний знак:
watermark.selectText.2=Текст водяного знаку: watermark.selectText.2=Текст водяного знаку:
watermark.selectText.3=Розмір шрифту: watermark.selectText.3=Розмір шрифту:
watermark.selectText.4=Обертання (0-360): watermark.selectText.4=Обертання (0-360):
watermark.selectText.5=Width Spacer (проміжок між кожним водяним знаком по горизонталі): watermark.selectText.5=widthSpacer (проміжок між кожним водяним знаком по горизонталі):
watermark.selectText.6=Height Spacer (проміжок між кожним водяним знаком по вертикалі): watermark.selectText.6=heightSpacer (проміжок між кожним водяним знаком по вертикалі):
watermark.selectText.7=Непрозорість (0% - 100%): watermark.selectText.7=Непрозорість (0% - 100%):
watermark.selectText.8=Тип водяного знаку: watermark.selectText.8=Тип водяного знаку:
watermark.selectText.9=Зображення водяного знаку: watermark.selectText.9=Зображення водяного знаку:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=Mã hóa
#watermark #watermark
watermark.title=Thêm hình mờ watermark.title=Thêm hình mờ
watermark.header=Thêm hình mờ watermark.header=Thêm hình mờ
watermark.customColor=Màu văn bản tùy chỉnh
watermark.selectText.1=Chọn PDF để thêm hình mờ: watermark.selectText.1=Chọn PDF để thêm hình mờ:
watermark.selectText.2=Văn bản hình mờ: watermark.selectText.2=Văn bản hình mờ:
watermark.selectText.3=Cỡ chữ: watermark.selectText.3=Cỡ chữ:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=Split PDF by Chapters
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
splitPdfByChapters.tags=split,chapters,bookmarks,organize splitPdfByChapters.tags=split,chapters,bookmarks,organize
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=Replace-Invert-Color replace-color.title=Replace-Invert-Color
replace-color.header=Replace-Invert Color PDF replace-color.header=Replace-Invert Color PDF
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,7 +1050,6 @@ addPassword.submit=加密
#watermark #watermark
watermark.title=添加水印 watermark.title=添加水印
watermark.header=添加水印 watermark.header=添加水印
watermark.customColor=自定义文本颜色
watermark.selectText.1=选择要添加水印的PDF watermark.selectText.1=选择要添加水印的PDF
watermark.selectText.2=水印文本: watermark.selectText.2=水印文本:
watermark.selectText.3=字体大小: watermark.selectText.3=字体大小:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for
splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF.
splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs.
splitByChapters.submit=Split PDF splitByChapters.submit=Split PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -512,10 +512,6 @@ home.splitPdfByChapters.title=依章節分割 PDF
home.splitPdfByChapters.desc=根據 PDF 的章節結構將其分割成多個檔案。 home.splitPdfByChapters.desc=根據 PDF 的章節結構將其分割成多個檔案。
splitPdfByChapters.tags=分割,章節,書籤,整理 splitPdfByChapters.tags=分割,章節,書籤,整理
home.validateSignature.title=Validate PDF Signature
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
#replace-invert-color #replace-invert-color
replace-color.title=取代-反轉顏色 replace-color.title=取代-反轉顏色
replace-color.header=取代-反轉 PDF 顏色 replace-color.header=取代-反轉 PDF 顏色
@@ -962,8 +958,6 @@ multiTool.moveLeft=Move Left
multiTool.moveRight=Move Right multiTool.moveRight=Move Right
multiTool.delete=Delete multiTool.delete=Delete
multiTool.dragDropMessage=Page(s) Selected multiTool.dragDropMessage=Page(s) Selected
multiTool.undo=Undo
multiTool.redo=Redo
#multiTool-advert #multiTool-advert
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features! multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
@@ -1056,13 +1050,12 @@ addPassword.submit=加密
#watermark #watermark
watermark.title=新增浮水印 watermark.title=新增浮水印
watermark.header=新增浮水印 watermark.header=新增浮水印
watermark.customColor=自訂文字顏色
watermark.selectText.1=選擇要新增浮水印的 PDF watermark.selectText.1=選擇要新增浮水印的 PDF
watermark.selectText.2=浮水印文字: watermark.selectText.2=浮水印文字:
watermark.selectText.3=字型大小: watermark.selectText.3=字型大小:
watermark.selectText.4=旋轉0-360 watermark.selectText.4=旋轉0-360
watermark.selectText.5=Width Spacer每個浮水印之間的水平間距 watermark.selectText.5=widthSpacer每個浮水印之間的水平間距
watermark.selectText.6=Height Spacer每個浮水印之間的垂直間距 watermark.selectText.6=heightSpacer每個浮水印之間的垂直間距
watermark.selectText.7=不透明度0% - 100% watermark.selectText.7=不透明度0% - 100%
watermark.selectText.8=浮水印類型: watermark.selectText.8=浮水印類型:
watermark.selectText.9=浮水印影像: watermark.selectText.9=浮水印影像:
@@ -1267,51 +1260,3 @@ splitByChapters.desc.2=書籤層級選擇用於分割的書籤層級0 表
splitByChapters.desc.3=包含中繼資料:如果勾選,原始 PDF 的中繼資料將包含在每個分割後的 PDF 中。 splitByChapters.desc.3=包含中繼資料:如果勾選,原始 PDF 的中繼資料將包含在每個分割後的 PDF 中。
splitByChapters.desc.4=允許重複:如果勾選,允許同一頁面上的多個書籤建立獨立的 PDF。 splitByChapters.desc.4=允許重複:如果勾選,允許同一頁面上的多個書籤建立獨立的 PDF。
splitByChapters.submit=分割 PDF splitByChapters.submit=分割 PDF
#File Chooser
fileChooser.click=Click
fileChooser.or=or
fileChooser.dragAndDrop=Drag & Drop
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
#release notes
releases.footer=Releases
releases.title=Release Notes
releases.header=Release Notes
releases.current.version=Current Release
releases.note=Release notes are only available in English
#Validate Signature
validateSignature.title=Validate PDF Signatures
validateSignature.header=Validate Digital Signatures
validateSignature.selectPDF=Select signed PDF file
validateSignature.submit=Validate Signatures
validateSignature.results=Validation Results
validateSignature.status=Status
validateSignature.signer=Signer
validateSignature.date=Date
validateSignature.reason=Reason
validateSignature.location=Location
validateSignature.noSignatures=No digital signatures found in this document
validateSignature.status.valid=Valid
validateSignature.status.invalid=Invalid
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
validateSignature.cert.expired=Certificate has expired
validateSignature.cert.revoked=Certificate has been revoked
validateSignature.signature.info=Signature Information
validateSignature.signature=Signature
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
validateSignature.cert.info=Certificate Details
validateSignature.cert.issuer=Issuer
validateSignature.cert.subject=Subject
validateSignature.cert.serialNumber=Serial Number
validateSignature.cert.validFrom=Valid From
validateSignature.cert.validUntil=Valid Until
validateSignature.cert.algorithm=Algorithm
validateSignature.cert.keySize=Key Size
validateSignature.cert.version=Version
validateSignature.cert.keyUsage=Key Usage
validateSignature.cert.selfSigned=Self-Signed
validateSignature.cert.bits=bits

View File

@@ -16,7 +16,7 @@ security:
csrfDisabled: true # set to 'true' to disable CSRF protection (not recommended for production) csrfDisabled: true # set to 'true' to disable CSRF protection (not recommended for production)
loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1 loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
loginMethod: all # Accepts values like 'all' and 'normal'(only Login with Username/Password), 'oauth2'(only Login with OAuth2) or 'saml2'(only Login with SAML2) loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
initialLogin: initialLogin:
username: '' # initial username for the first login username: '' # initial username for the first login
password: '' # initial password for the first login password: '' # initial password for the first login
@@ -42,14 +42,14 @@ security:
issuer: '' # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) endpoint issuer: '' # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) endpoint
clientId: '' # client ID from your provider clientId: '' # client ID from your provider
clientSecret: '' # client secret from your provider clientSecret: '' # client secret from your provider
autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
useAsUsername: email # default is 'email'; custom fields can be used as the username useAsUsername: email # default is 'email'; custom fields can be used as the username
scopes: openid, profile, email # specify the scopes for which the application will request permissions scopes: openid, profile, email # specify the scopes for which the application will request permissions
provider: google # set this to your OAuth provider's name, e.g., 'google' or 'keycloak' provider: google # set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
saml2: saml2:
enabled: false # Only enabled for paid enterprise clients (enterpriseEdition.enabled must be true) enabled: false # currently in alpha, not recommended for use yet, enableAlphaFunctionality must be set to true
autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
registrationId: stirling registrationId: stirling
idpMetadataUri: https://dev-XXXXXXXX.okta.com/app/externalKey/sso/saml/metadata idpMetadataUri: https://dev-XXXXXXXX.okta.com/app/externalKey/sso/saml/metadata

View File

@@ -407,7 +407,7 @@
{ {
"moduleName": "commons-io:commons-io", "moduleName": "commons-io:commons-io",
"moduleUrl": "https://commons.apache.org/proper/commons-io/", "moduleUrl": "https://commons.apache.org/proper/commons-io/",
"moduleVersion": "2.18.0", "moduleVersion": "2.17.0",
"moduleLicense": "Apache-2.0", "moduleLicense": "Apache-2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
}, },
@@ -1386,13 +1386,6 @@
"moduleLicense": "Apache License, Version 2.0", "moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
}, },
{
"moduleName": "org.springframework.session:spring-session-core",
"moduleUrl": "https://spring.io/projects/spring-session",
"moduleVersion": "3.4.0",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{ {
"moduleName": "org.springframework:spring-aop", "moduleName": "org.springframework:spring-aop",
"moduleUrl": "https://github.com/spring-projects/spring-framework", "moduleUrl": "https://github.com/spring-projects/spring-framework",

View File

@@ -1,221 +1,10 @@
.custom-file-chooser {
display: flex;
flex-direction: column;
position: relative;
min-height: 55px;
border-radius: 1rem;
--selected-files-display: none;
}
.input-container {
position: relative;
border-radius: 1rem;
border: 1px dashed rgb(105, 116, 134);
column-gap: 7px;
row-gap: 7px;
height: 150px;
width: 100%;
--overlay-display: none;
transition: background-color 0.5s linear;
}
.input-container:hover {
outline: none;
border: none;
background-color: var(--md-sys-color-surface-container-low);
-webkit-transition: box-shadow 1s ease, background-color 2s linear;
-moz-transition: box-shadow 1s ease, background-color 2s linear;
-o-transition: box-shadow 1s ease, background-color 2s linear;
-ms-transition: box-shadow 1s ease, background-color 2s linear;
transition: box-shadow 1s ease, background-color 2s linear;
box-shadow: 0 0 10px rgb(105, 116, 134);
cursor: pointer;
}
.input-container * {
user-select: none;
pointer-events: none;
}
.input-container::before {
display: var(--overlay-display);
position: absolute;
content: '';
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: var(--md-sys-color-surface);
z-index: 1;
white-space: pre;
border-radius: 1rem;
}
.input-container::after {
display: var(--overlay-display);
position: absolute;
content: attr(data-text);
font-size: 0.9rem;
font-weight: 550;
color: var(--md-sys-color-on-surface);
background-color: transparent;
min-width: 150px;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
text-align: center;
z-index: 2;
}
.input-container input[type="file"] {
display: none;
}
.input-container div:nth-of-type(2) {
color: var(--md-sys-color-on-surface);
}
.input-container div:nth-of-type(1), .input-container div:nth-of-type(3) {
color: var(--md-sys-color-on-surface);
font-size: 16px;
font-weight: bold;
}
.file-input-btn {
display: inline-block;
border: 1px solid #ccc;
padding: 6px 12px;
cursor: pointer;
color: #212529;
font-size: 1rem;
border-radius: 3rem;
background-color: #DDE0E3;
}
.small-file-container {
padding-top: 1px;
position: relative;
row-gap: 1px;
height: 60px;
width: 60px;
}
.file-icon {
display: flex;
align-items: center;
justify-content: center;
height: 30px;
width: 30px;
}
.file-icon * {
height: inherit;
width: inherit;
}
.file-info {
min-width: 0;
}
.file-info > div:nth-child(1) {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--md-sys-color-on-surface);
max-width: 60px;
font-size: 0.75rem;
}
.file-info > div:nth-child(2) {
overflow: hidden;
text-overflow: ellipsis;
color: grey;
max-width: 60px;
font-size: 10px;
}
.remove-selected-file {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
height: 15px;
width: 15px;
right: 10px;
top: -5px;
}
.remove-selected-file * {
overflow: hidden;
height: inherit;
width: inherit;
z-index: 3;
pointer-events: none;
user-select: none;
}
.remove-selected-file:after {
content: '';
position: absolute;
left: 1;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: white;
z-index: 2;
user-select: none;
pointer-events: none;
}
.remove-selected-file:hover {
cursor: pointer;
}
.custom-file-label { .custom-file-label {
padding-right: 90px; padding-right: 90px;
} }
.selected-files { .selected-files {
display: var(--selected-files-display); margin-top: 10px;
padding-left: 5px; max-height: 150px;
padding-right: 3px; overflow-y: auto;
padding-top: 15px;
padding-bottom: 15px;
flex: 1;
white-space: pre-wrap; white-space: pre-wrap;
row-gap: 12px;
column-gap: 5px;
border-radius: 1rem;
border: 1px solid rgb(105, 116, 134, 0.5);
} }

View File

@@ -1,219 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ir" viewBox="0 0 640 480">
<defs>
<clipPath id="ir-a">
<path fill-opacity=".7" d="M-85.3 0h682.7v512H-85.3z"/>
</clipPath>
</defs>
<g fill-rule="evenodd" clip-path="url(#ir-a)" transform="translate(80)scale(.9375)">
<path fill="#fff" d="M-192 0h896v512h-896z"/>
<path fill="#da0000" d="M-192 343.8h896V512h-896z"/>
<g fill="#fff" stroke-width="1pt">
<path d="M-21.6 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
<path d="M52.4 367.7v3.4H33.8v-3.4zm-34.6-7.9H21v11.3h-3.3z"/>
<path d="M49.6 351H53v20h-3.4zm-8.4 0h3.3v20h-3.3zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
<path d="M17.8 359.9H21V371h-3.3z"/>
<path d="M17.8 359.9H21V371h-3.3z"/>
<path d="M17.8 359.9H21V371h-3.3zm-39.3 0h3.3V371h-3.3zm28.8 0h3.4V371H7.3zm-14.3 0h3.4V371H-7z"/>
<path d="M9.6 367.7v3.4H-5.5v-3.4zm1-8.7v3.4H1V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M-102.2 351h49v3.3h-49zm7.3 16.8h3.4v3.3H-95zm41.9 0v3.3h-9.8v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
<path d="M-28.2 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.3v11.3h-3.3z"/>
<path d="M-31 351h3.4v20H-31zm-8.4 0h3.3v20h-3.3zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
<path d="M-62.8 359.9h3.3V371h-3.3z"/>
<path d="M-62.8 359.9h3.3V371h-3.3z"/>
<path d="M-62.8 359.9h3.3V371h-3.3zm-39.3 0h3.3V371h-3.3zm28.8 0h3.3V371h-3.3zm-14.3 0h3.4V371h-3.4z"/>
<path d="M-71 367.7v3.4h-15v-3.4zm1-8.7v3.4h-9.6V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M58.3 351h49v3.3h-49zm7.3 16.8H69v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zm5.3-16.8h3.4v20h-3.4z"/>
<path d="M132.3 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
<path d="M129.5 351h3.4v20h-3.4zm-8.4 0h3.4v20H121zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
<path d="M97.7 359.9h3.4V371h-3.4z"/>
<path d="M97.7 359.9h3.4V371h-3.4z"/>
<path d="M97.7 359.9h3.4V371h-3.4zm-39.3 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.4z"/>
<path d="M89.6 367.7v3.4H74.4v-3.4zm1-8.7v3.4H81V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M622.7 351h49v3.3h-49zm7.3 16.8h3.4v3.3H630zm41.9 0v3.3H662v-3.4zm5.3-16.8h3.3v20h-3.4z"/>
<path d="M696.7 367.7v3.4H678v-3.4zm-34.6-7.9h3.4v11.3H662z"/>
<path d="M694 351h3.3v20h-3.4zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
<path d="M662 359.9h3.5V371H662z"/>
<path d="M662 359.9h3.5V371H662z"/>
<path d="M662 359.9h3.5V371H662zm-39.2 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.4z"/>
<path d="M654 367.7v3.4h-15.2v-3.4zm1-8.7v3.4h-9.6V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M138.7 351h49.1v3.3h-49zm7.4 16.8h3.3v3.3h-3.3zm41.8 0v3.3h-9.8v-3.4zm5.3-16.8h3.4v20h-3.4z"/>
<path d="M212.8 367.7v3.4h-18.6v-3.4zm-34.7-7.9h3.4v11.3h-3.4z"/>
<path d="M210 351h3.4v20H210zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-17.9V359zm39.3 0v3.4h-17.9V359z"/>
<path d="M178.1 359.9h3.4V371h-3.4z"/>
<path d="M178.1 359.9h3.4V371h-3.4z"/>
<path d="M178.1 359.9h3.4V371h-3.4zm-39.3 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.2 0h3.3V371h-3.3z"/>
<path d="M170 367.7v3.4h-15.1v-3.4zm1-8.7v3.4h-9.6V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M219.5 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zM274 351h3.3v20H274z"/>
<path d="M293.5 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
<path d="M290.7 351h3.4v20h-3.4zm-8.4 0h3.4v20h-3.4zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
<path d="M258.9 359.9h3.4V371h-3.4z"/>
<path d="M258.9 359.9h3.4V371h-3.4z"/>
<path d="M258.9 359.9h3.4V371h-3.4zm-39.3 0h3.3V371h-3.3zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371H234z"/>
<path d="M250.8 367.7v3.4h-15.2v-3.4zm1-8.7v3.4H242V359z"/>
</g>
<path fill="#239f40" d="M-192 0h896v168.2h-896z"/>
<g fill="#fff" stroke-width="1pt">
<path d="M300.7 351h49v3.3h-49zm7.3 16.8h3.4v3.3H308zm41.9 0v3.3H340v-3.4zm5.3-16.8h3.3v20h-3.3z"/>
<path d="M374.7 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3H340z"/>
<path d="M372 351h3.3v20H372zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
<path d="M340 359.9h3.5V371H340z"/>
<path d="M340 359.9h3.5V371H340z"/>
<path d="M340 359.9h3.5V371H340zm-39.2 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.4z"/>
<path d="M332 367.7v3.4h-15.2v-3.4zm1-8.7v3.4h-9.6V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M381.4 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm42 0v3.3h-9.9v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
<path d="M455.4 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
<path d="M452.7 351h3.3v20h-3.3zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-17.9V359zm39.3 0v3.4h-17.9V359z"/>
<path d="M420.8 359.9h3.4V371h-3.4z"/>
<path d="M420.8 359.9h3.4V371h-3.4z"/>
<path d="M420.8 359.9h3.4V371h-3.4zm-39.3 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.3z"/>
<path d="M412.7 367.7v3.4h-15.1v-3.4zm1-8.7v3.4H404V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M462.2 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
<path d="M536.2 367.7v3.4h-18.6v-3.4zm-34.7-7.9h3.4v11.3h-3.4z"/>
<path d="M533.4 351h3.4v20h-3.4zm-8.4 0h3.3v20H525zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
<path d="M501.6 359.9h3.3V371h-3.3z"/>
<path d="M501.6 359.9h3.3V371h-3.3z"/>
<path d="M501.6 359.9h3.3V371h-3.3zm-39.4 0h3.4V371h-3.4zm28.9 0h3.3V371h-3.3zm-14.3 0h3.4V371h-3.4z"/>
<path d="M493.4 367.7v3.4h-15.1v-3.4zm1-8.7v3.4h-9.6V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M543.4 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm41.9 0v3.3h-9.8v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
<path d="M617.4 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.3v11.3h-3.3z"/>
<path d="M614.6 351h3.4v20h-3.4zm-8.4 0h3.3v20h-3.3zm-44.8 8v3.4h-18V359zm39.3 0v3.4h-18V359z"/>
<path d="M582.8 359.9h3.3V371h-3.3z"/>
<path d="M582.8 359.9h3.3V371h-3.3z"/>
<path d="M582.8 359.9h3.3V371h-3.3zm-39.3 0h3.3V371h-3.3zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371H558z"/>
<path d="M574.6 367.7v3.4h-15.1v-3.4zm1-8.7v3.4H566V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M-183.8 351h49v3.3h-49zm7.3 16.8h3.4v3.3h-3.4zm42 0v3.3h-9.9v-3.4zm5.2-16.8h3.4v20h-3.4z"/>
<path d="M-109.8 367.7v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
<path d="M-112.5 351h3.3v20h-3.3zm-8.5 0h3.4v20h-3.4zm-44.8 8v3.4h-17.9V359zm39.3 0v3.4h-17.9V359z"/>
<path d="M-144.4 359.9h3.4V371h-3.4z"/>
<path d="M-144.4 359.9h3.4V371h-3.4z"/>
<path d="M-144.4 359.9h3.4V371h-3.4zm-39.3 0h3.4V371h-3.4zm28.8 0h3.4V371h-3.4zm-14.3 0h3.4V371h-3.4z"/>
<path d="M-152.5 367.7v3.4h-15.2v-3.4zm1-8.7v3.4h-9.6V359z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M-21.6 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
<path d="M52.4 160.2v3.4H33.8v-3.4zm-34.6-7.9H21v11.3h-3.3z"/>
<path d="M49.6 143.4H53v20.2h-3.4zm-8.4 0h3.3v20.2h-3.3zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
<path d="M17.8 152.3H21v11.3h-3.3z"/>
<path d="M17.8 152.3H21v11.3h-3.3z"/>
<path d="M17.8 152.3H21v11.3h-3.3zm-39.3 0h3.3v11.3h-3.3zm28.8 0h3.4v11.3H7.3zm-14.3 0h3.4v11.3H-7z"/>
<path d="M9.6 160.2v3.4H-5.5v-3.4zm1-8.7v3.3H1v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M-102.2 143.4h49v3.4h-49zm7.3 17h3.4v3.2H-95zm41.9-.2v3.4h-9.8v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
<path d="M-28.2 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.3v11.3h-3.3z"/>
<path d="M-31 143.4h3.4v20.2H-31zm-8.4 0h3.3v20.2h-3.3zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
<path d="M-62.8 152.3h3.3v11.3h-3.3z"/>
<path d="M-62.8 152.3h3.3v11.3h-3.3z"/>
<path d="M-62.8 152.3h3.3v11.3h-3.3zm-39.3 0h3.3v11.3h-3.3zm28.8 0h3.3v11.3h-3.3zm-14.3 0h3.4v11.3h-3.4z"/>
<path d="M-71 160.2v3.4h-15v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M58.3 143.4h49v3.4h-49zm7.3 17H69v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.3-16.8h3.4v20.2h-3.4z"/>
<path d="M132.3 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
<path d="M129.5 143.4h3.4v20.2h-3.4zm-8.4 0h3.4v20.2H121zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
<path d="M97.7 152.3h3.4v11.3h-3.4z"/>
<path d="M97.7 152.3h3.4v11.3h-3.4z"/>
<path d="M97.7 152.3h3.4v11.3h-3.4zm-39.3 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.4z"/>
<path d="M89.6 160.2v3.4H74.4v-3.4zm1-8.7v3.3H81v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M622.7 143.4h49v3.4h-49zm7.3 17h3.4v3.2H630zm41.9-.2v3.4H662v-3.4zm5.3-16.8h3.3v20.2h-3.4z"/>
<path d="M696.7 160.2v3.4H678v-3.4zm-34.6-7.9h3.4v11.3H662z"/>
<path d="M694 143.4h3.3v20.2h-3.4zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
<path d="M662 152.3h3.5v11.3H662z"/>
<path d="M662 152.3h3.5v11.3H662z"/>
<path d="M662 152.3h3.5v11.3H662zm-39.2 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.4z"/>
<path d="M654 160.2v3.4h-15.2v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M138.7 143.4h49.1v3.4h-49zm7.4 17h3.3v3.2h-3.3zm41.8-.2v3.4h-9.8v-3.4zm5.3-16.8h3.4v20.2h-3.4z"/>
<path d="M212.8 160.2v3.4h-18.6v-3.4zm-34.7-7.9h3.4v11.3h-3.4z"/>
<path d="M210 143.4h3.4v20.2H210zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-17.9v-3.3zm39.3 0v3.4h-17.9v-3.3z"/>
<path d="M178.1 152.3h3.4v11.3h-3.4z"/>
<path d="M178.1 152.3h3.4v11.3h-3.4z"/>
<path d="M178.1 152.3h3.4v11.3h-3.4zm-39.3 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.2 0h3.3v11.3h-3.3z"/>
<path d="M170 160.2v3.4h-15.1v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M219.5 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.3-16.8h3.3v20.2H274z"/>
<path d="M293.5 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
<path d="M290.7 143.4h3.4v20.2h-3.4zm-8.4 0h3.4v20.2h-3.4zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
<path d="M258.9 152.3h3.4v11.3h-3.4z"/>
<path d="M258.9 152.3h3.4v11.3h-3.4z"/>
<path d="M258.9 152.3h3.4v11.3h-3.4zm-39.3 0h3.3v11.3h-3.3zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3H234z"/>
<path d="M250.8 160.2v3.4h-15.2v-3.4zm1-8.7v3.3H242v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M300.7 143.4h49v3.4h-49zm7.3 17h3.4v3.2H308zm41.9-.2v3.4H340v-3.4zm5.3-16.8h3.3v20.2h-3.3z"/>
<path d="M374.7 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3H340z"/>
<path d="M372 143.4h3.3v20.2H372zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
<path d="M340 152.3h3.5v11.3H340z"/>
<path d="M340 152.3h3.5v11.3H340z"/>
<path d="M340 152.3h3.5v11.3H340zm-39.2 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.4z"/>
<path d="M332 160.2v3.4h-15.2v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M381.4 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm42-.2v3.4h-9.9v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
<path d="M455.4 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
<path d="M452.7 143.4h3.3v20.2h-3.3zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-17.9v-3.3zm39.3 0v3.4h-17.9v-3.3z"/>
<path d="M420.8 152.3h3.4v11.3h-3.4z"/>
<path d="M420.8 152.3h3.4v11.3h-3.4z"/>
<path d="M420.8 152.3h3.4v11.3h-3.4zm-39.3 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.3z"/>
<path d="M412.7 160.2v3.4h-15.1v-3.4zm1-8.7v3.3H404v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M462.2 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
<path d="M536.2 160.2v3.4h-18.6v-3.4zm-34.7-7.9h3.4v11.3h-3.4z"/>
<path d="M533.4 143.4h3.4v20.2h-3.4zm-8.4 0h3.3v20.2H525zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
<path d="M501.6 152.3h3.3v11.3h-3.3z"/>
<path d="M501.6 152.3h3.3v11.3h-3.3z"/>
<path d="M501.6 152.3h3.3v11.3h-3.3zm-39.4 0h3.4v11.3h-3.4zm28.9 0h3.3v11.3h-3.3zm-14.3 0h3.4v11.3h-3.4z"/>
<path d="M493.4 160.2v3.4h-15.1v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M543.4 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm41.9-.2v3.4h-9.8v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
<path d="M617.4 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.3v11.3h-3.3z"/>
<path d="M614.6 143.4h3.4v20.2h-3.4zm-8.4 0h3.3v20.2h-3.3zm-44.8 8v3.4h-18v-3.3zm39.3 0v3.4h-18v-3.3z"/>
<path d="M582.8 152.3h3.3v11.3h-3.3z"/>
<path d="M582.8 152.3h3.3v11.3h-3.3z"/>
<path d="M582.8 152.3h3.3v11.3h-3.3zm-39.3 0h3.3v11.3h-3.3zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3H558z"/>
<path d="M574.6 160.2v3.4h-15.1v-3.4zm1-8.7v3.3H566v-3.3z"/>
</g>
<g fill="#fff" stroke-width="1pt">
<path d="M-183.8 143.4h49v3.4h-49zm7.3 17h3.4v3.2h-3.4zm42-.2v3.4h-9.9v-3.4zm5.2-16.8h3.4v20.2h-3.4z"/>
<path d="M-109.8 160.2v3.4h-18.6v-3.4zm-34.6-7.9h3.4v11.3h-3.4z"/>
<path d="M-112.5 143.4h3.3v20.2h-3.3zm-8.5 0h3.4v20.2h-3.4zm-44.8 8v3.4h-17.9v-3.3zm39.3 0v3.4h-17.9v-3.3z"/>
<path d="M-144.4 152.3h3.4v11.3h-3.4z"/>
<path d="M-144.4 152.3h3.4v11.3h-3.4z"/>
<path d="M-144.4 152.3h3.4v11.3h-3.4zm-39.3 0h3.4v11.3h-3.4zm28.8 0h3.4v11.3h-3.4zm-14.3 0h3.4v11.3h-3.4z"/>
<path d="M-152.5 160.2v3.4h-15.2v-3.4zm1-8.7v3.3h-9.6v-3.3z"/>
</g>
<path fill="#d90000" d="M-68.8 339.5h6V350h-6zm160.5 0h6V350h-6zm-283.7 0h6V350h-6zm81.5 0h6V350h-6zm80.9 0h6V350h-6zm40 0h6V350h-6zm40.9 0h6V350h-6zm80.4 0h6V350h-6zm203 0h6.1V350h-6zm-162.1 0h6V350h-6zm40 0h6V350h-6zm40.5 0h6V350h-6zm40.4 0h6V350h-6zm323.2 0h6V350h-6zm-242.7 0h6V350h-6zm40.8 0h6V350h-6zm41.3 0h6V350h-6zm38.8 0h6V350h-6zm41.3 0h6V350h-6zm40.4 0h6V350h-6zm119.7 0h6V350h-6zm-38.8 0h6V350h-6zm-808.9 0h6V350h-6z"/>
<path fill="#239e3f" d="M-68.8 162.6h6v10.5h-6zm160.5 0h6v10.5h-6zm-283.7 0h6v10.5h-6zm81.5 0h6v10.5h-6zm80.9 0h6v10.5h-6zm40 0h6v10.5h-6zm40.9 0h6v10.5h-6zm80.4 0h6v10.5h-6zm203 0h6.1v10.5h-6zm-162.1 0h6v10.5h-6zm40 0h6v10.5h-6zm40.5 0h6v10.5h-6zm40.4 0h6v10.5h-6zm323.2 0h6v10.5h-6zm-242.7 0h6v10.5h-6zm40.8 0h6v10.5h-6zm41.3 0h6v10.5h-6zm38.8 0h6v10.5h-6zm41.3 0h6v10.5h-6zm40.4 0h6v10.5h-6zm119.7 0h6v10.5h-6zm-38.8 0h6v10.5h-6zm-808.9 0h6v10.5h-6z"/>
<g fill="#da0000">
<path d="M279.8 197.5c8.4 10.4 34.5 67.6-15.7 105.2-23.7 17.8-9 18.6-8.3 21.6 38-20.1 50.3-47.5 50-72-.2-24.4-13.2-46-26-54.8"/>
<path d="M284.8 194.8a73.3 73.3 0 0 1 15.7 112.4c27.2-6 62-86.4-15.7-112.4m-57.6 0a73.3 73.3 0 0 0-15.6 112.4c-27.3-6-62-86.4 15.6-112.4"/>
<path d="M232.2 197.5c-8.4 10.4-34.5 67.6 15.7 105.2 23.6 17.8 9 18.6 8.3 21.6-38-20.1-50.3-47.5-50-72 .2-24.4 13.2-46 26-54.8"/>
<path d="M304.2 319.1c-14.9.2-33.6-2-47.5-9.3 2.3 4.5 4.2 7.3 6.5 11.7 13.2 1.3 31.5 2.8 41-2.4m-95 0c14.9.2 33.6-2 47.5-9.3-2.3 4.5-4.2 7.3-6.5 11.7-13.2 1.3-31.5 2.8-41-2.4m27.3-138.7c3 8 10.9 9.2 19.3 4.5 6.2 3.6 15.7 3.9 19-4.1 2.5 19.8-18.3 15-19 11.2-7.8 7.5-22.2 3.2-19.3-11.6"/>
<path d="m256.4 331.6 7.8-9 1.1-120.1-9.3-8.2-9.3 7.8 1.9 121z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,36 +1,26 @@
(function () { (function() {
if (window.isDownloadScriptInitialized) return; // Prevent re-execution
window.isDownloadScriptInitialized = true;
const { const { pdfPasswordPrompt, multipleInputsForSingleRequest, disableMultipleFiles, remoteCall, sessionExpired, refreshPage, error } = window.stirlingPDF;
pdfPasswordPrompt,
multipleInputsForSingleRequest,
disableMultipleFiles,
remoteCall,
sessionExpired,
refreshPage,
error,
} = window.stirlingPDF;
function showErrorBanner(message, stackTrace) { function showErrorBanner(message, stackTrace) {
const errorContainer = document.getElementById('errorContainer'); const errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = 'block'; // Display the banner errorContainer.style.display = "block"; // Display the banner
errorContainer.querySelector('.alert-heading').textContent = error; errorContainer.querySelector(".alert-heading").textContent = error;
errorContainer.querySelector('p').textContent = message; errorContainer.querySelector("p").textContent = message;
document.querySelector('#traceContent').textContent = stackTrace; document.querySelector("#traceContent").textContent = stackTrace;
} }
function showSessionExpiredPrompt() { function showSessionExpiredPrompt() {
const errorContainer = document.getElementById('errorContainer'); const errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = 'block'; errorContainer.style.display = "block";
errorContainer.querySelector('.alert-heading').textContent = sessionExpired; errorContainer.querySelector(".alert-heading").textContent = sessionExpired;
errorContainer.querySelector('p').textContent = sessionExpired; errorContainer.querySelector("p").textContent = sessionExpired;
document.querySelector('#traceContent').textContent = ''; document.querySelector("#traceContent").textContent = "";
// Optional: Add a refresh button // Optional: Add a refresh button
const refreshButton = document.createElement('button'); const refreshButton = document.createElement("button");
refreshButton.textContent = refreshPage; refreshButton.textContent = refreshPage;
refreshButton.className = 'btn btn-primary mt-3'; refreshButton.className = "btn btn-primary mt-3";
refreshButton.onclick = () => location.reload(); refreshButton.onclick = () => location.reload();
errorContainer.appendChild(refreshButton); errorContainer.appendChild(refreshButton);
} }
@@ -38,19 +28,19 @@
let firstErrorOccurred = false; let firstErrorOccurred = false;
$(document).ready(function () { $(document).ready(function () {
$('form').submit(async function (event) { $("form").submit(async function (event) {
event.preventDefault(); event.preventDefault();
firstErrorOccurred = false; firstErrorOccurred = false;
const url = this.action; const url = this.action;
const files = $('#fileInput-input')[0].files; const files = $("#fileInput-input")[0].files;
const formData = new FormData(this); const formData = new FormData(this);
const submitButton = document.getElementById('submitBtn'); const submitButton = document.getElementById("submitBtn");
const showGameBtn = document.getElementById('show-game-btn'); const showGameBtn = document.getElementById("show-game-btn");
const originalButtonText = submitButton.textContent; const originalButtonText = submitButton.textContent;
var boredWaiting = localStorage.getItem('boredWaiting') || 'disabled'; var boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
if (showGameBtn) { if (showGameBtn) {
showGameBtn.style.display = 'none'; showGameBtn.style.display = "none";
} }
// Remove empty file entries // Remove empty file entries
@@ -59,60 +49,58 @@
formData.delete(key); formData.delete(key);
} }
} }
const override = $('#override').val() || ''; const override = $("#override").val() || "";
console.log(override); console.log(override);
// Set a timeout to show the game button if operation takes more than 5 seconds // Set a timeout to show the game button if operation takes more than 5 seconds
const timeoutId = setTimeout(() => { const timeoutId = setTimeout(() => {
if (boredWaiting === 'enabled' && showGameBtn) { if (boredWaiting === "enabled" && showGameBtn) {
showGameBtn.style.display = 'block'; showGameBtn.style.display = "block";
showGameBtn.parentNode.insertBefore(document.createElement('br'), showGameBtn.nextSibling); showGameBtn.parentNode.insertBefore(document.createElement('br'), showGameBtn.nextSibling);
} }
}, 5000); }, 5000);
try { try {
submitButton.textContent = 'Processing...'; submitButton.textContent = "Processing...";
submitButton.disabled = true; submitButton.disabled = true;
if (remoteCall === true) { if (remoteCall === true) {
if (override === 'multi' || (!multipleInputsForSingleRequest && files.length > 1 && override !== 'single')) { if (override === "multi" || (!multipleInputsForSingleRequest && files.length > 1 && override !== "single")) {
await submitMultiPdfForm(url, files); await submitMultiPdfForm(url, files);
} else { } else {
await handleSingleDownload(url, formData); await handleSingleDownload(url, formData);
} }
} }
//clearFileInput();
clearFileInput();
clearTimeout(timeoutId); clearTimeout(timeoutId);
if (showGameBtn) { if (showGameBtn) {
showGameBtn.style.display = 'none'; showGameBtn.style.display = "none";
showGameBtn.style.marginTop = ''; showGameBtn.style.marginTop = "";
} }
submitButton.textContent = originalButtonText; submitButton.textContent = originalButtonText;
submitButton.disabled = false; submitButton.disabled = false;
// After process finishes, check for boredWaiting and gameDialog open status // After process finishes, check for boredWaiting and gameDialog open status
const gameDialog = document.getElementById('game-container-wrapper'); const gameDialog = document.getElementById('game-container-wrapper');
if (boredWaiting === 'enabled' && gameDialog && gameDialog.open) { if (boredWaiting === "enabled" && gameDialog && gameDialog.open) {
// Display a green banner at the bottom of the screen saying "Download complete" // Display a green banner at the bottom of the screen saying "Download complete"
let downloadCompleteText = 'Download Complete'; let downloadCompleteText = "Download Complete";
if (window.downloadCompleteText) { if(window.downloadCompleteText){
downloadCompleteText = window.downloadCompleteText; downloadCompleteText = window.downloadCompleteText;
} }
$('body').append( $("body").append('<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">'+ downloadCompleteText + '</div>');
'<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">' + setTimeout(function() {
downloadCompleteText + $("#download-complete-banner").fadeOut("slow", function() {
'</div>'
);
setTimeout(function () {
$('#download-complete-banner').fadeOut('slow', function () {
$(this).remove(); // Remove the banner after fading out $(this).remove(); // Remove the banner after fading out
}); });
}, 5000); // Banner will fade out after 5 seconds }, 5000); // Banner will fade out after 5 seconds
} }
} catch (error) { } catch (error) {
clearTimeout(timeoutId); clearTimeout(timeoutId);
showGameBtn.style.display = 'none'; showGameBtn.style.display = "none";
submitButton.textContent = originalButtonText; submitButton.textContent = originalButtonText;
submitButton.disabled = false; submitButton.disabled = false;
handleDownloadError(error); handleDownloadError(error);
@@ -124,8 +112,8 @@
async function getPDFPageCount(file) { async function getPDFPageCount(file) {
try { try {
const arrayBuffer = await file.arrayBuffer(); const arrayBuffer = await file.arrayBuffer();
pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs-legacy/pdf.worker.mjs'; pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs-legacy/pdf.worker.mjs'
const pdf = await pdfjsLib.getDocument({data: arrayBuffer}).promise; const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
return pdf.numPages; return pdf.numPages;
} catch (error) { } catch (error) {
console.error('Error getting PDF page count:', error); console.error('Error getting PDF page count:', error);
@@ -140,8 +128,8 @@
let errorMessage = null; let errorMessage = null;
try { try {
const response = await fetch(url, {method: 'POST', body: formData}); const response = await fetch(url, { method: "POST", body: formData });
const contentType = response.headers.get('content-type'); const contentType = response.headers.get("content-type");
if (!response.ok) { if (!response.ok) {
errorMessage = response.status; errorMessage = response.status;
@@ -149,44 +137,45 @@
showSessionExpiredPrompt(); showSessionExpiredPrompt();
return; return;
} }
if (contentType && contentType.includes('application/json')) { if (contentType && contentType.includes("application/json")) {
console.error('Throwing error banner, response was not okay'); console.error("Throwing error banner, response was not okay");
return handleJsonResponse(response); return handleJsonResponse(response);
} }
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }
const contentDisposition = response.headers.get('Content-Disposition'); const contentDisposition = response.headers.get("Content-Disposition");
let filename = getFilenameFromContentDisposition(contentDisposition); let filename = getFilenameFromContentDisposition(contentDisposition);
const blob = await response.blob(); const blob = await response.blob();
success = true; success = true;
if (contentType.includes('application/pdf') || contentType.includes('image/')) { if (contentType.includes("application/pdf") || contentType.includes("image/")) {
//clearFileInput(); clearFileInput();
return handleResponse(blob, filename, !isMulti, isZip); return handleResponse(blob, filename, !isMulti, isZip);
} else { } else {
//clearFileInput(); clearFileInput();
return handleResponse(blob, filename, false, isZip); return handleResponse(blob, filename, false, isZip);
} }
} catch (error) { } catch (error) {
success = false; success = false;
errorMessage = error.message; errorMessage = error.message;
console.error('Error in handleSingleDownload:', error); console.error("Error in handleSingleDownload:", error);
throw error; throw error;
} finally { } finally {
const processingTime = performance.now() - startTime; const processingTime = performance.now() - startTime;
// Capture analytics // Capture analytics
const pageCount = file && file.type === 'application/pdf' ? await getPDFPageCount(file) : null; const pageCount = file && file.type === 'application/pdf' ? await getPDFPageCount(file) : null;
if (analyticsEnabled) { if(analyticsEnabled) {
posthog.capture('file_processing', { posthog.capture('file_processing', {
success: success, success: success,
file_type: file ? file.type || 'unknown' : 'unknown', file_type: file ? file.type || 'unknown' : 'unknown',
file_size: file ? file.size : 0, file_size: file ? file.size : 0,
processing_time: processingTime, processing_time: processingTime,
error_message: errorMessage, error_message: errorMessage,
pdf_pages: pageCount, pdf_pages: pageCount
}); });
} }
} }
@@ -195,11 +184,11 @@
function getFilenameFromContentDisposition(contentDisposition) { function getFilenameFromContentDisposition(contentDisposition) {
let filename; let filename;
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) {
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim(); filename = decodeURIComponent(contentDisposition.split("filename=")[1].replace(/"/g, "")).trim();
} else { } else {
// If the Content-Disposition header is not present or does not contain the filename, use a default filename // If the Content-Disposition header is not present or does not contain the filename, use a default filename
filename = 'download'; filename = "download";
} }
return filename; return filename;
@@ -209,37 +198,37 @@
const json = await response.json(); const json = await response.json();
const errorMessage = JSON.stringify(json, null, 2); const errorMessage = JSON.stringify(json, null, 2);
if ( if (
errorMessage.toLowerCase().includes('the password is incorrect') || errorMessage.toLowerCase().includes("the password is incorrect") ||
errorMessage.toLowerCase().includes('Password is not provided') || errorMessage.toLowerCase().includes("Password is not provided") ||
errorMessage.toLowerCase().includes('PDF contains an encryption dictionary') errorMessage.toLowerCase().includes("PDF contains an encryption dictionary")
) { ) {
if (!firstErrorOccurred) { if (!firstErrorOccurred) {
firstErrorOccurred = true; firstErrorOccurred = true;
alert(pdfPasswordPrompt); alert(pdfPasswordPrompt);
} }
} else { } else {
showErrorBanner(json.error + ':' + json.message, json.trace); showErrorBanner(json.error + ":" + json.message, json.trace);
} }
} }
async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) { async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) {
if (!blob) return; if (!blob) return;
const downloadOption = localStorage.getItem('downloadOption'); const downloadOption = localStorage.getItem("downloadOption");
if (considerViewOptions) { if (considerViewOptions) {
if (downloadOption === 'sameWindow') { if (downloadOption === "sameWindow") {
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
window.location.href = url; window.location.href = url;
return; return;
} else if (downloadOption === 'newWindow') { } else if (downloadOption === "newWindow") {
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
window.open(url, '_blank'); window.open(url, "_blank");
return; return;
} }
} }
if (!isZip) { if (!isZip) {
downloadFile(blob, filename); downloadFile(blob, filename);
} }
return {filename, blob}; return { filename, blob };
} }
function handleDownloadError(error) { function handleDownloadError(error) {
@@ -251,32 +240,32 @@
function downloadFile(blob, filename) { function downloadFile(blob, filename) {
if (!(blob instanceof Blob)) { if (!(blob instanceof Blob)) {
console.error('Invalid blob passed to downloadFile function'); console.error("Invalid blob passed to downloadFile function");
return; return;
} }
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const a = document.createElement('a'); const a = document.createElement("a");
a.href = url; a.href = url;
a.download = filename; a.download = filename;
a.click(); a.click();
urls.push(url); // Store the URL so it doesn't get garbage collected too soon urls.push(url); // Store the URL so it doesn't get garbage collected too soon
return {filename, blob}; return { filename, blob };
} }
async function submitMultiPdfForm(url, files) { async function submitMultiPdfForm(url, files) {
const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4; const zipThreshold = parseInt(localStorage.getItem("zipThreshold"), 10) || 4;
const zipFiles = files.length > zipThreshold; const zipFiles = files.length > zipThreshold;
let jszip = null; let jszip = null;
// Add Space below Progress Bar before Showing // Add Space below Progress Bar before Showing
$('.progressBarContainer').after($('<br>')); $('.progressBarContainer').after($('<br>'));
$('.progressBarContainer').show(); $(".progressBarContainer").show();
// Initialize the progress bar // Initialize the progress bar
let progressBar = $('.progressBar'); let progressBar = $(".progressBar");
progressBar.css('width', '0%'); progressBar.css("width", "0%");
progressBar.attr('aria-valuenow', 0); progressBar.attr("aria-valuenow", 0);
progressBar.attr('aria-valuemax', files.length); progressBar.attr("aria-valuemax", files.length);
if (zipFiles) { if (zipFiles) {
jszip = new JSZip(); jszip = new JSZip();
@@ -290,10 +279,10 @@
if (postForm) { if (postForm) {
formData = new FormData($(postForm)[0]); // Convert the form to a jQuery object and get the raw DOM element formData = new FormData($(postForm)[0]); // Convert the form to a jQuery object and get the raw DOM element
} else { } else {
console.log('No form with POST method found.'); console.log("No form with POST method found.");
} }
//Remove file to reuse parameters for other runs //Remove file to reuse parameters for other runs
formData.delete('fileInput'); formData.delete("fileInput");
// Remove empty file entries // Remove empty file entries
for (let [key, value] of formData.entries()) { for (let [key, value] of formData.entries()) {
if (value instanceof File && !value.name) { if (value instanceof File && !value.name) {
@@ -309,12 +298,12 @@
for (const chunk of chunks) { for (const chunk of chunks) {
const promises = chunk.map(async (file) => { const promises = chunk.map(async (file) => {
let fileFormData = new FormData(); let fileFormData = new FormData();
fileFormData.append('fileInput', file); fileFormData.append("fileInput", file);
console.log(fileFormData); console.log(fileFormData);
// Add other form data // Add other form data
for (let pair of formData.entries()) { for (let pair of formData.entries()) {
fileFormData.append(pair[0], pair[1]); fileFormData.append(pair[0], pair[1]);
console.log(pair[0] + ', ' + pair[1]); console.log(pair[0] + ", " + pair[1]);
} }
try { try {
@@ -336,47 +325,47 @@
if (zipFiles) { if (zipFiles) {
try { try {
const content = await jszip.generateAsync({type: 'blob'}); const content = await jszip.generateAsync({ type: "blob" });
downloadFile(content, 'files.zip'); downloadFile(content, "files.zip");
} catch (error) { } catch (error) {
console.error('Error generating ZIP file: ' + error); console.error("Error generating ZIP file: " + error);
} }
} }
progressBar.css('width', '100%'); progressBar.css("width", "100%");
progressBar.attr('aria-valuenow', Array.from(files).length); progressBar.attr("aria-valuenow", Array.from(files).length);
} }
function updateProgressBar(progressBar, files) { function updateProgressBar(progressBar, files) {
let progress = (progressBar.attr('aria-valuenow') / files.length) * 100 + 100 / files.length; let progress = (progressBar.attr("aria-valuenow") / files.length) * 100 + 100 / files.length;
progressBar.css('width', progress + '%'); progressBar.css("width", progress + "%");
progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1); progressBar.attr("aria-valuenow", parseInt(progressBar.attr("aria-valuenow")) + 1);
} }
window.addEventListener('unload', () => { window.addEventListener("unload", () => {
for (const url of urls) { for (const url of urls) {
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
} }
}); });
// Clear file input after job // Clear file input after job
function clearFileInput() { function clearFileInput(){
let pathname = document.location.pathname; let pathname = document.location.pathname;
if (pathname != '/merge-pdfs') { if(pathname != "/merge-pdfs"){
let formElement = document.querySelector('#fileInput-input'); let formElement = document.querySelector("#fileInput-input");
formElement.value = ''; formElement.value = '';
let editSectionElement = document.querySelector('#editSection'); let editSectionElement = document.querySelector("#editSection");
if (editSectionElement) { if(editSectionElement){
editSectionElement.style.display = 'none'; editSectionElement.style.display = "none";
} }
let cropPdfCanvas = document.querySelector('#cropPdfCanvas'); let cropPdfCanvas = document.querySelector("#cropPdfCanvas");
let overlayCanvas = document.querySelector('#overlayCanvas'); let overlayCanvas = document.querySelector("#overlayCanvas");
if (cropPdfCanvas && overlayCanvas) { if(cropPdfCanvas && overlayCanvas){
cropPdfCanvas.width = 0; cropPdfCanvas.width = 0;
cropPdfCanvas.height = 0; cropPdfCanvas.height = 0;
overlayCanvas.width = 0; overlayCanvas.width = 0;
overlayCanvas.height = 0; overlayCanvas.height = 0;
} }
} else { } else{
console.log("Disabled for 'Merge'"); console.log("Disabled for 'Merge'");
} }
} }

View File

@@ -1,52 +0,0 @@
class FileIconFactory {
static createFileIcon(fileExtension) {
let ext = fileExtension.toLowerCase();
switch (ext) {
case "pdf":
return this.createPDFIcon();
case "csv":
return this.createCSVIcon();
case "jpe":
case "jpg":
case "jpeg":
case "gif":
case "png":
case "bmp":
case "ico":
case "svg":
case "svgz":
case "tif":
case "tiff":
case "ai":
case "drw":
case "pct":
case "psp":
case "xcf":
case "psd":
case "raw":
case "webp":
case "heic":
return this.createImageIcon();
default:
return this.createUnknownFileIcon();
}
}
static createPDFIcon() {
return `
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-filetype-pdf" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M14 4.5V14a2 2 0 0 1-2 2h-1v-1h1a1 1 0 0 0 1-1V4.5h-2A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v9H2V2a2 2 0 0 1 2-2h5.5zM1.6 11.85H0v3.999h.791v-1.342h.803q.43 0 .732-.173.305-.175.463-.474a1.4 1.4 0 0 0 .161-.677q0-.375-.158-.677a1.2 1.2 0 0 0-.46-.477q-.3-.18-.732-.179m.545 1.333a.8.8 0 0 1-.085.38.57.57 0 0 1-.238.241.8.8 0 0 1-.375.082H.788V12.48h.66q.327 0 .512.181.185.183.185.522m1.217-1.333v3.999h1.46q.602 0 .998-.237a1.45 1.45 0 0 0 .595-.689q.196-.45.196-1.084 0-.63-.196-1.075a1.43 1.43 0 0 0-.589-.68q-.396-.234-1.005-.234zm.791.645h.563q.371 0 .609.152a.9.9 0 0 1 .354.454q.118.302.118.753a2.3 2.3 0 0 1-.068.592 1.1 1.1 0 0 1-.196.422.8.8 0 0 1-.334.252 1.3 1.3 0 0 1-.483.082h-.563zm3.743 1.763v1.591h-.79V11.85h2.548v.653H7.896v1.117h1.606v.638z"/>
</svg>
`;
}
static createImageIcon() {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M216-144q-30 0-51-21.5T144-216v-528q0-29 21-50.5t51-21.5h528q30 0 51 21.5t21 50.5v528q0 29-21 50.5T744-144H216Zm48-144h432L552-480 444-336l-72-96-108 144Z"/></svg>`;
}
static createUnknownFileIcon() {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M263.72-96Q234-96 213-117.15T192-168v-624q0-29.7 21.15-50.85Q234.3-864 264-864h312l192 192v504q0 29.7-21.16 50.85Q725.68-96 695.96-96H263.72ZM528-624h168L528-792v168Z"/></svg>`;
}
}
export default FileIconFactory;

View File

@@ -1,31 +0,0 @@
class FileUtils {
static extractFileExtension(filename) {
if (!filename || filename.trim().length <= 0) return "";
let trimmedName = filename.trim();
return trimmedName.substring(trimmedName.lastIndexOf(".") + 1);
}
static transformFileSize(size) {
if (!size) return `0Bs`;
let oneKB = 1024;
let oneMB = oneKB * 1024;
let oneGB = oneMB * 1024;
let oneTB = oneGB * 1024;
if (size < oneKB) return `${this._toFixed(size)}Bs`;
else if (oneKB <= size && size < oneMB) return `${this._toFixed(size / oneKB)}KBs`;
else if (oneMB <= size && size < oneGB) return `${this._toFixed(size / oneMB)}MBs`;
else if (oneGB <= size && size < oneTB) return `${this._toFixed(size / oneGB)}GBs`;
else return `${this._toFixed(size / oneTB)}TBs`;
}
static _toFixed(val, digits = 1) {
// Return value without ending 0s after decimal point
// Example: if res == 145.0 then return 145, else if 145.x (where x != 0) return 145.x
let res = val.toFixed(digits);
let resRounded = (res|0);
return res == resRounded ? resRounded : res;
}
}
export default FileUtils;

View File

@@ -1,92 +1,72 @@
import FileIconFactory from "./file-icon-factory.js"; document.addEventListener("DOMContentLoaded", function () {
import FileUtils from "./file-utils.js";
import UUID from './uuid.js';
let isScriptExecuted = false;
if (!isScriptExecuted) {
isScriptExecuted = true;
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll(".custom-file-chooser").forEach(setupFileInput); document.querySelectorAll(".custom-file-chooser").forEach(setupFileInput);
}); });
}
function setupFileInput(chooser) { function setupFileInput(chooser) {
const elementId = chooser.getAttribute("data-bs-element-id"); const elementId = chooser.getAttribute("data-bs-element-id");
const filesSelected = chooser.getAttribute("data-bs-files-selected"); const filesSelected = chooser.getAttribute("data-bs-files-selected");
const pdfPrompt = chooser.getAttribute("data-bs-pdf-prompt"); const pdfPrompt = chooser.getAttribute("data-bs-pdf-prompt");
const inputContainerId = chooser.getAttribute('data-bs-element-container-id');
let inputContainer = document.getElementById(inputContainerId);
let allFiles = []; let allFiles = [];
let overlay; let overlay;
let dragCounter = 0; let dragCounter = 0;
inputContainer.addEventListener('click', (e) => {
let inputBtn = document.getElementById(elementId);
inputBtn.click();
})
const dragenterListener = function () { const dragenterListener = function () {
dragCounter++; dragCounter++;
if (!overlay) { if (!overlay) {
// Show overlay by removing display: none from pseudo elements (::before and ::after) overlay = document.createElement("div");
inputContainer.style.setProperty('--overlay-display', "''"); overlay.style.position = "fixed";
overlay = true; overlay.style.top = 0;
overlay.style.left = 0;
overlay.style.width = "100%";
overlay.style.height = "100%";
overlay.style.background = "rgba(0, 0, 0, 0.5)";
overlay.style.color = "#fff";
overlay.style.zIndex = "1000";
overlay.style.display = "flex";
overlay.style.alignItems = "center";
overlay.style.justifyContent = "center";
overlay.style.pointerEvents = "none";
overlay.innerHTML = "<p>Drop files anywhere to upload</p>";
document.getElementById("content-wrap").appendChild(overlay);
} }
}; };
const dragleaveListener = function () { const dragleaveListener = function () {
dragCounter--; dragCounter--;
if (dragCounter === 0) { if (dragCounter === 0) {
hideOverlay(); if (overlay) {
overlay.remove();
overlay = null;
}
} }
}; };
function hideOverlay() {
if (!overlay) return;
inputContainer.style.setProperty('--overlay-display', 'none');
overlay = false;
}
const dropListener = function (e) { const dropListener = function (e) {
e.preventDefault(); e.preventDefault();
// Drag and Drop shall only affect the target file chooser
if (e.target !== inputContainer) {
hideOverlay();
dragCounter = 0;
return;
}
const dt = e.dataTransfer; const dt = e.dataTransfer;
const files = dt.files; const files = dt.files;
const fileInput = document.getElementById(elementId); for (let i = 0; i < files.length; i++) {
if (fileInput?.hasAttribute("multiple")) { allFiles.push(files[i]);
pushFileListTo(files, allFiles);
} else if (fileInput) {
allFiles = [files[0]];
} }
const dataTransfer = new DataTransfer(); const dataTransfer = new DataTransfer();
allFiles.forEach((file) => dataTransfer.items.add(file)); allFiles.forEach((file) => dataTransfer.items.add(file));
const fileInput = document.getElementById(elementId);
fileInput.files = dataTransfer.files; fileInput.files = dataTransfer.files;
hideOverlay(); if (overlay) {
overlay.remove();
overlay = null;
}
dragCounter = 0; dragCounter = 0;
fileInput.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: {source: 'drag-drop'} })); fileInput.dispatchEvent(new Event("change", { bubbles: true }));
}; };
function pushFileListTo(fileList, container) {
for (let file of fileList) {
container.push(file);
}
}
["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
document.body.addEventListener(eventName, preventDefaults, false); document.body.addEventListener(eventName, preventDefaults, false);
}); });
@@ -101,132 +81,32 @@ function setupFileInput(chooser) {
document.body.addEventListener("drop", dropListener); document.body.addEventListener("drop", dropListener);
$("#" + elementId).on("change", function (e) { $("#" + elementId).on("change", function (e) {
let element = e.target; allFiles = Array.from(e.target.files);
const isDragAndDrop = e.detail?.source == 'drag-drop';
if (element instanceof HTMLInputElement && element.hasAttribute("multiple")) {
allFiles = isDragAndDrop ? allFiles : [... allFiles, ... element.files];
} else {
allFiles = Array.from(isDragAndDrop ? allFiles : [element.files[0]]);
}
allFiles = allFiles.map(file => {
if (!file.uniqueId) file.uniqueId = UUID.uuidv4();
return file;
});
if (!isDragAndDrop) {
let dataTransfer = toDataTransfer(allFiles);
element.files = dataTransfer.files;
}
handleFileInputChange(this); handleFileInputChange(this);
this.dispatchEvent(new CustomEvent("file-input-change", { bubbles: true })); });
});
function toDataTransfer(files) {
let dataTransfer = new DataTransfer();
files.forEach(file => dataTransfer.items.add(file));
return dataTransfer;
}
function handleFileInputChange(inputElement) { function handleFileInputChange(inputElement) {
const files = allFiles; const files = allFiles;
showOrHideSelectedFilesContainer(files); const fileNames = files.map((f) => f.name);
const selectedFilesContainer = $(inputElement).siblings(".selected-files");
const filesInfo = files.map((f) => ({name: f.name, size: f.size, uniqueId: f.uniqueId}));
const selectedFilesContainer = $(inputContainer).siblings(".selected-files");
selectedFilesContainer.empty(); selectedFilesContainer.empty();
filesInfo.forEach((info) => { fileNames.forEach((fileName) => {
let fileContainerClasses = 'small-file-container d-flex flex-column justify-content-center align-items-center'; selectedFilesContainer.append("<div>" + fileName + "</div>");
let fileContainer = document.createElement('div');
$(fileContainer).addClass(fileContainerClasses);
$(fileContainer).attr('id', info.uniqueId);
let fileIconContainer = createFileIconContainer(info);
let fileInfoContainer = createFileInfoContainer(info);
let removeBtn = document.createElement('div');
removeBtn.classList.add('remove-selected-file');
let removeBtnIconHTML = `<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#C02223"><path d="m339-288 141-141 141 141 51-51-141-141 141-141-51-51-141 141-141-141-51 51 141 141-141 141 51 51ZM480-96q-79 0-149-30t-122.5-82.5Q156-261 126-331T96-480q0-80 30-149.5t82.5-122Q261-804 331-834t149-30q80 0 149.5 30t122 82.5Q804-699 834-629.5T864-480q0 79-30 149t-82.5 122.5Q699-156 629.5-126T480-96Z"/></svg>`;
$(removeBtn).append(removeBtnIconHTML);
$(removeBtn).attr('data-file-id', info.uniqueId).click(removeFileListener);
$(fileContainer).append(fileIconContainer);
$(fileContainer).append(fileInfoContainer);
$(fileContainer).append(removeBtn);
selectedFilesContainer.append(fileContainer);
}); });
if (fileNames.length === 1) {
showOrHideSelectedFilesContainer(filesInfo); $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
} else if (fileNames.length > 1) {
$(inputElement)
.siblings(".custom-file-label")
.addClass("selected")
.html(fileNames.length + " " + filesSelected);
} else {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt);
} }
function showOrHideSelectedFilesContainer(files) {
if (files && files.length > 0)
chooser.style.setProperty('--selected-files-display', 'flex');
else
chooser.style.setProperty('--selected-files-display', 'none');
} }
function removeFileListener(e) {
const fileId = (e.target).getAttribute('data-file-id');
let inputElement = document.getElementById(elementId);
removeFileById(fileId, inputElement);
showOrHideSelectedFilesContainer(allFiles);
inputElement.dispatchEvent(new CustomEvent("file-input-change", { bubbles: true }));
}
function removeFileById(fileId, inputElement) {
let fileContainer = document.getElementById(fileId);
fileContainer.remove();
allFiles = allFiles.filter(v => v.uniqueId != fileId);
let dataTransfer = toDataTransfer(allFiles);
if (inputElement) inputElement.files = dataTransfer.files;
}
function createFileIconContainer(info) {
let fileIconContainer = document.createElement('div');
fileIconContainer.classList.add('file-icon');
// Add icon based on the extension
let fileExtension = FileUtils.extractFileExtension(info.name);
let fileIcon = FileIconFactory.createFileIcon(fileExtension);
$(fileIconContainer).append(fileIcon);
return fileIconContainer;
}
function createFileInfoContainer(info) {
let fileInfoContainer = document.createElement("div");
let fileInfoContainerClasses = 'file-info d-flex flex-column align-items-center justify-content-center';
$(fileInfoContainer).addClass(fileInfoContainerClasses);
$(fileInfoContainer).append(
`<div title="${info.name}">${info.name}</div>`
);
let fileSizeWithUnits = FileUtils.transformFileSize(info.size);
$(fileInfoContainer).append(
`<div title="${info.size}">${fileSizeWithUnits}</div>`
);
return fileInfoContainer;
}
//Listen for event of file being removed and the filter it out of the allFiles array //Listen for event of file being removed and the filter it out of the allFiles array
document.addEventListener("fileRemoved", function (e) { document.addEventListener("fileRemoved", function (e) {
const fileId = e.detail; const fileName = e.detail;
let inputElement = document.getElementById(elementId); allFiles = allFiles.filter(file => file.name !== fileName);
removeFileById(fileId, inputElement);
showOrHideSelectedFilesContainer(allFiles);
}); });
} }

View File

@@ -3,7 +3,7 @@ let currentSort = {
descending: false, descending: false,
}; };
document.getElementById("fileInput-input").addEventListener("file-input-change", function () { document.getElementById("fileInput-input").addEventListener("change", function () {
var files = this.files; var files = this.files;
displayFiles(files); displayFiles(files);
}); });
@@ -29,7 +29,6 @@ async function displayFiles(files) {
// Create filename div and set textContent to sanitize // Create filename div and set textContent to sanitize
const fileNameDiv = document.createElement("div"); const fileNameDiv = document.createElement("div");
fileNameDiv.className = "filename"; fileNameDiv.className = "filename";
fileNameDiv.setAttribute("data-file-id", files[i].uniqueId);
fileNameDiv.textContent = files[i].name; fileNameDiv.textContent = files[i].name;
// Create page info div and set textContent to sanitize // Create page info div and set textContent to sanitize
@@ -111,13 +110,11 @@ function attachMoveButtons() {
event.preventDefault(); event.preventDefault();
var parent = this.closest(".list-group-item"); var parent = this.closest(".list-group-item");
//Get name of removed file //Get name of removed file
let filenameNode = parent.querySelector(".filename"); var fileName = parent.querySelector(".filename").innerText;
var fileName = filenameNode.innerText;
const fileId = filenameNode.getAttribute("data-file-id");
parent.remove(); parent.remove();
updateFiles(); updateFiles();
//Dispatch a custom event with the name of the removed file //Dispatch a custom event with the name of the removed file
var event = new CustomEvent("fileRemoved", { detail: fileId }); var event = new CustomEvent("fileRemoved", { detail: fileName });
document.dispatchEvent(event); document.dispatchEvent(event);
}); });
} }

View File

@@ -1,20 +1,12 @@
import { DeletePageCommand } from "./commands/delete-page.js";
import { SelectPageCommand } from "./commands/select.js";
import { SplitFileCommand } from "./commands/split.js";
import { UndoManager } from "./UndoManager.js";
class PdfActionsManager { class PdfActionsManager {
pageDirection; pageDirection;
pagesContainer; pagesContainer;
static selectedPages = []; // Static property shared across all instances static selectedPages = []; // Static property shared across all instances
undoManager;
constructor(id, undoManager) { constructor(id) {
this.pagesContainer = document.getElementById(id); this.pagesContainer = document.getElementById(id);
this.pageDirection = document.documentElement.getAttribute("dir"); this.pageDirection = document.documentElement.getAttribute("dir");
this.undoManager = undoManager || new UndoManager();
var styleElement = document.createElement("link"); var styleElement = document.createElement("link");
styleElement.rel = "stylesheet"; styleElement.rel = "stylesheet";
styleElement.href = "css/pdfActions.css"; styleElement.href = "css/pdfActions.css";
@@ -35,8 +27,7 @@ class PdfActionsManager {
const sibling = imgContainer.previousSibling; const sibling = imgContainer.previousSibling;
if (sibling) { if (sibling) {
let movePageCommand = this.movePageTo(imgContainer, sibling, true, true); this.movePageTo(imgContainer, sibling, true);
this._pushUndoClearRedo(movePageCommand);
} }
} }
@@ -44,12 +35,7 @@ class PdfActionsManager {
var imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
const sibling = imgContainer.nextSibling; const sibling = imgContainer.nextSibling;
if (sibling) { if (sibling) {
let movePageCommand = this.movePageTo( this.movePageTo(imgContainer, sibling.nextSibling, true);
imgContainer,
sibling.nextSibling,
true
);
this._pushUndoClearRedo(movePageCommand);
} }
} }
@@ -57,27 +43,30 @@ class PdfActionsManager {
var imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
const img = imgContainer.querySelector("img"); const img = imgContainer.querySelector("img");
let rotateCommand = this.rotateElement(img, -90); this.rotateElement(img, -90);
this._pushUndoClearRedo(rotateCommand);
} }
rotateCWButtonCallback(e) { rotateCWButtonCallback(e) {
var imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
const img = imgContainer.querySelector("img"); const img = imgContainer.querySelector("img");
let rotateCommand = this.rotateElement(img, 90); this.rotateElement(img, 90);
this._pushUndoClearRedo(rotateCommand);
} }
deletePageButtonCallback(e) { deletePageButtonCallback(e) {
let imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
let deletePageCommand = new DeletePageCommand( this.pagesContainer.removeChild(imgContainer);
imgContainer, if (this.pagesContainer.childElementCount === 0) {
this.pagesContainer const filenameInput = document.getElementById("filename-input");
); const filenameParagraph = document.getElementById("filename");
deletePageCommand.execute(); const downloadBtn = document.getElementById("export-button");
this._pushUndoClearRedo(deletePageCommand); filenameInput.disabled = true;
filenameInput.value = "";
filenameParagraph.innerText = "";
downloadBtn.disabled = true;
}
} }
insertFileButtonCallback(e) { insertFileButtonCallback(e) {
@@ -92,15 +81,7 @@ class PdfActionsManager {
splitFileButtonCallback(e) { splitFileButtonCallback(e) {
var imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
imgContainer.classList.toggle("split-before");
let splitFileCommand = new SplitFileCommand(imgContainer, "split-before");
splitFileCommand.execute();
this._pushUndoClearRedo(splitFileCommand);
}
_pushUndoClearRedo(command) {
this.undoManager.pushUndoClearRedo(command);
} }
setActions({ movePageTo, addFiles, rotateElement }) { setActions({ movePageTo, addFiles, rotateElement }) {
@@ -178,10 +159,25 @@ class PdfActionsManager {
selectCheckbox.onchange = () => { selectCheckbox.onchange = () => {
const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1; const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1;
let selectPageCommand = new SelectPageCommand(pageNumber, selectCheckbox); if (selectCheckbox.checked) {
selectPageCommand.execute(); //adds to array of selected pages
window.selectedPages.push(pageNumber);
} else {
//remove page from selected pages array
const index = window.selectedPages.indexOf(pageNumber);
if (index !== -1) {
window.selectedPages.splice(index, 1);
}
}
this._pushUndoClearRedo(selectPageCommand); if (window.selectedPages.length > 0 && !window.selectPage) {
window.toggleSelectPageVisibility();
}
if (window.selectedPages.length == 0 && window.selectPage) {
window.toggleSelectPageVisibility();
}
window.updateSelectedPagesDisplay();
}; };
const insertFileButtonContainer = document.createElement("div"); const insertFileButtonContainer = document.createElement("div");

View File

@@ -1,20 +1,11 @@
import {MovePageUpCommand, MovePageDownCommand} from './commands/move-page.js';
import {RemoveSelectedCommand} from './commands/remove.js';
import {RotateAllCommand, RotateElementCommand} from './commands/rotate.js';
import {SplitAllCommand} from './commands/split.js';
import {UndoManager} from './UndoManager.js';
import {PageBreakCommand} from './commands/page-break.js';
import {AddFilesCommand} from './commands/add-page.js';
class PdfContainer { class PdfContainer {
fileName; fileName;
pagesContainer; pagesContainer;
pagesContainerWrapper; pagesContainerWrapper;
pdfAdapters; pdfAdapters;
downloadLink; downloadLink;
undoManager;
constructor(id, wrapperId, pdfAdapters, undoManager) { constructor(id, wrapperId, pdfAdapters) {
this.pagesContainer = document.getElementById(id); this.pagesContainer = document.getElementById(id);
this.pagesContainerWrapper = document.getElementById(wrapperId); this.pagesContainerWrapper = document.getElementById(wrapperId);
this.downloadLink = null; this.downloadLink = null;
@@ -36,12 +27,10 @@ class PdfContainer {
this.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay.bind(this); this.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay.bind(this);
this.toggleSelectPageVisibility = this.toggleSelectPageVisibility.bind(this); this.toggleSelectPageVisibility = this.toggleSelectPageVisibility.bind(this);
this.updatePagesFromCSV = this.updatePagesFromCSV.bind(this); this.updatePagesFromCSV = this.updatePagesFromCSV.bind(this);
this.addFilesBlankAll = this.addFilesBlankAll.bind(this); this.addFilesBlankAll = this.addFilesBlankAll.bind(this)
this.removeAllElements = this.removeAllElements.bind(this); this.removeAllElements = this.removeAllElements.bind(this);
this.resetPages = this.resetPages.bind(this); this.resetPages = this.resetPages.bind(this);
this.undoManager = undoManager || new UndoManager();
this.pdfAdapters = pdfAdapters; this.pdfAdapters = pdfAdapters;
this.pdfAdapters.forEach((adapter) => { this.pdfAdapters.forEach((adapter) => {
@@ -65,141 +54,102 @@ class PdfContainer {
window.updatePagesFromCSV = this.updatePagesFromCSV; window.updatePagesFromCSV = this.updatePagesFromCSV;
window.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay; window.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay;
window.updatePageNumbersAndCheckboxes = this.updatePageNumbersAndCheckboxes; window.updatePageNumbersAndCheckboxes = this.updatePageNumbersAndCheckboxes;
window.addFilesBlankAll = this.addFilesBlankAll; window.addFilesBlankAll = this.addFilesBlankAll
window.removeAllElements = this.removeAllElements; window.removeAllElements = this.removeAllElements;
window.resetPages = this.resetPages; window.resetPages = this.resetPages;
let undoBtn = document.getElementById('undo-btn'); const filenameInput = document.getElementById("filename-input");
let redoBtn = document.getElementById('redo-btn'); const downloadBtn = document.getElementById("export-button");
document.addEventListener('undo-manager-update', (e) => {
let canUndo = e.detail.canUndo;
let canRedo = e.detail.canRedo;
undoBtn.disabled = !canUndo;
redoBtn.disabled = !canRedo;
});
window.undo = () => {
if (undoManager.canUndo()) undoManager.undo();
else {
undoBtn.disabled = !undoManager.canUndo();
redoBtn.disabled = !undoManager.canRedo();
}
};
window.redo = () => {
if (undoManager.canRedo()) undoManager.redo();
else {
undoBtn.disabled = !undoManager.canUndo();
redoBtn.disabled = !undoManager.canRedo();
}
};
const filenameInput = document.getElementById('filename-input');
const downloadBtn = document.getElementById('export-button');
filenameInput.onkeyup = this.updateFilename; filenameInput.onkeyup = this.updateFilename;
filenameInput.onkeydown = this.preventIllegalChars; filenameInput.onkeydown = this.preventIllegalChars;
filenameInput.disabled = false; filenameInput.disabled = false;
filenameInput.innerText = ''; filenameInput.innerText = "";
downloadBtn.disabled = true; downloadBtn.disabled = true;
} }
movePageTo(startElement, endElement, scrollTo = false, moveUp = false) { movePageTo(startElement, endElement, scrollTo = false) {
let movePageCommand; const childArray = Array.from(this.pagesContainer.childNodes);
if (moveUp) { const startIndex = childArray.indexOf(startElement);
movePageCommand = new MovePageUpCommand( const endIndex = childArray.indexOf(endElement);
startElement,
endElement, // Check & remove page number elements here too if they exist because Firefox doesn't fire the relevant event on page move.
this.pagesContainer, const pageNumberElement = startElement.querySelector(".page-number");
this.pagesContainerWrapper, if (pageNumberElement) {
scrollTo startElement.removeChild(pageNumberElement);
); }
this.pagesContainer.removeChild(startElement);
if (!endElement) {
this.pagesContainer.append(startElement);
} else { } else {
movePageCommand = new MovePageDownCommand( this.pagesContainer.insertBefore(startElement, endElement);
startElement,
endElement,
this.pagesContainer,
this.pagesContainerWrapper,
scrollTo
);
} }
movePageCommand.execute(); if (scrollTo) {
return movePageCommand; const { width } = startElement.getBoundingClientRect();
const vector = endIndex !== -1 && startIndex > endIndex ? 0 - width : width;
this.pagesContainerWrapper.scroll({
left: this.pagesContainerWrapper.scrollLeft + vector,
});
}
} }
async addFiles(element) { addFiles(nextSiblingElement, blank = false) {
let addFilesCommand = new AddFilesCommand( if (blank) {
element,
window.selectedPages,
this.addFilesAction.bind(this),
this.pagesContainer
);
await addFilesCommand.execute(); this.addFilesBlank(nextSiblingElement);
this.undoManager.pushUndoClearRedo(addFilesCommand); } else {
} var input = document.createElement("input");
input.type = "file";
async addFilesAction(nextSiblingElement) {
let pages = [];
return new Promise((resolve) => {
var input = document.createElement('input');
input.type = 'file';
input.multiple = true; input.multiple = true;
input.setAttribute('accept', 'application/pdf,image/*'); input.setAttribute("accept", "application/pdf,image/*");
input.onchange = async (e) => { input.onchange = async (e) => {
const files = e.target.files; const files = e.target.files;
if (files.length > 0) {
pages = await this.addFilesFromFiles(files, nextSiblingElement, pages); this.addFilesFromFiles(files, nextSiblingElement);
this.updateFilename(files[0].name); this.updateFilename(files ? files[0].name : "");
const selectAll = document.getElementById('select-pages-container'); const selectAll = document.getElementById("select-pages-container");
selectAll.classList.toggle('hidden', false); selectAll.classList.toggle("hidden", false);
}
resolve(pages);
}; };
input.click(); input.click();
}); }
} }
async addFilesFromFiles(files, nextSiblingElement, pages) { async addFilesFromFiles(files, nextSiblingElement) {
this.fileName = files[0].name; this.fileName = files[0].name;
for (var i = 0; i < files.length; i++) { for (var i = 0; i < files.length; i++) {
const startTime = Date.now(); const startTime = Date.now();
let processingTime, let processingTime, errorMessage = null, pageCount = 0;
errorMessage = null,
pageCount = 0;
try { try {
const file = files[i]; const file = files[i];
if (file.type === 'application/pdf') { if (file.type === "application/pdf") {
const {renderer, pdfDocument} = await this.loadFile(file); const { renderer, pdfDocument } = await this.loadFile(file);
pageCount = renderer.pageCount || 0; pageCount = renderer.pageCount || 0;
pages = await this.addPdfFile(renderer, pdfDocument, nextSiblingElement, pages); await this.addPdfFile(renderer, pdfDocument, nextSiblingElement);
} else if (file.type.startsWith('image/')) { } else if (file.type.startsWith("image/")) {
pages = await this.addImageFile(file, nextSiblingElement, pages); await this.addImageFile(file, nextSiblingElement);
} }
processingTime = Date.now() - startTime; processingTime = Date.now() - startTime;
this.captureFileProcessingEvent(true, file, processingTime, null, pageCount); this.captureFileProcessingEvent(true, file, processingTime, null, pageCount);
} catch (error) { } catch (error) {
processingTime = Date.now() - startTime; processingTime = Date.now() - startTime;
errorMessage = error.message || 'Unknown error'; errorMessage = error.message || "Unknown error";
this.captureFileProcessingEvent(false, files[i], processingTime, errorMessage, pageCount); this.captureFileProcessingEvent(false, files[i], processingTime, errorMessage, pageCount);
} }
} }
document.querySelectorAll('.enable-on-file').forEach((element) => { document.querySelectorAll(".enable-on-file").forEach((element) => {
element.disabled = false; element.disabled = false;
}); });
return pages;
} }
captureFileProcessingEvent(success, file, processingTime, errorMessage, pageCount) { captureFileProcessingEvent(success, file, processingTime, errorMessage, pageCount) {
try { try{
if (analyticsEnabled) { if(analyticsEnabled){
posthog.capture('file_processing', { posthog.capture('file_processing', {
success, success,
file_type: file?.type || 'unknown', file_type: file?.type || 'unknown',
@@ -208,65 +158,96 @@ class PdfContainer {
error_message: errorMessage, error_message: errorMessage,
pdf_pages: pageCount, pdf_pages: pageCount,
}); });
} }
} catch {} }catch{
}
}
async addFilesBlank(nextSiblingElement) {
const pdfContent = `
%PDF-1.4
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Kids [3 0 R] /Count 1 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] /Contents 5 0 R >>
endobj
5 0 obj
<< /Length 44 >>
stream
0 0 0 595 0 842 re
W
n
endstream
endobj
xref
0 6
0000000000 65535 f
0000000010 00000 n
0000000071 00000 n
0000000121 00000 n
0000000205 00000 n
0000000400 00000 n
trailer
<< /Size 6 /Root 1 0 R >>
startxref
278
%%EOF
`;
const blob = new Blob([pdfContent], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const file = new File([blob], "blank_page.pdf", { type: "application/pdf" });
await this.addPdfFile(file, nextSiblingElement);
} }
async addFilesBlank(nextSiblingElement, pages) {
let doc = await PDFLib.PDFDocument.create();
let docBytes = await doc.save();
const url = URL.createObjectURL(new Blob([docBytes], {type: 'application/pdf'}));
const renderer = await this.toRenderer(url);
pages = await this.addPdfFile(renderer, doc, nextSiblingElement, pages);
return pages;
}
rotateElement(element, deg) { rotateElement(element, deg) {
let rotateCommand = new RotateElementCommand(element, deg); var lastTransform = element.style.rotate;
rotateCommand.execute(); if (!lastTransform) {
lastTransform = "0";
}
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
const newAngle = lastAngle + deg;
element.style.rotate = newAngle + "deg";
return rotateCommand;
} }
async addPdfFile(renderer, pdfDocument, nextSiblingElement, pages) { async addPdfFile(renderer, pdfDocument, nextSiblingElement) {
for (var i = 0; i < renderer.pageCount; i++) { for (var i = 0; i < renderer.pageCount; i++) {
const div = document.createElement('div'); const div = document.createElement("div");
div.classList.add('page-container'); div.classList.add("page-container");
div.id = 'page-container-' + (i + 1); div.id = "page-container-" + (i + 1);
var img = document.createElement('img'); var img = document.createElement("img");
img.classList.add('page-image'); img.classList.add("page-image");
const imageSrc = await renderer.renderPage(i); const imageSrc = await renderer.renderPage(i);
img.src = imageSrc; img.src = imageSrc;
img.pageIdx = i; img.pageIdx = i;
img.rend = renderer; img.rend = renderer;
img.doc = pdfDocument; img.doc = pdfDocument;
div.appendChild(img); div.appendChild(img);
this.pdfAdapters.forEach((adapter) => { this.pdfAdapters.forEach((adapter) => {
adapter.adapt?.(div); adapter.adapt?.(div);
}); });
if (nextSiblingElement) { if (nextSiblingElement) {
this.pagesContainer.insertBefore(div, nextSiblingElement); this.pagesContainer.insertBefore(div, nextSiblingElement);
} else { } else {
this.pagesContainer.appendChild(div); this.pagesContainer.appendChild(div);
} }
}
pages.push(div);
} }
return pages; async addImageFile(file, nextSiblingElement) {
} const div = document.createElement("div");
div.classList.add("page-container");
async addImageFile(file, nextSiblingElement, pages) { var img = document.createElement("img");
const div = document.createElement('div'); img.classList.add("page-image");
div.classList.add('page-container');
var img = document.createElement('img');
img.classList.add('page-image');
img.src = URL.createObjectURL(file); img.src = URL.createObjectURL(file);
div.appendChild(img); div.appendChild(img);
@@ -278,19 +259,17 @@ class PdfContainer {
} else { } else {
this.pagesContainer.appendChild(div); this.pagesContainer.appendChild(div);
} }
pages.push(div);
return pages;
} }
async loadFile(file) { async loadFile(file) {
var objectUrl = URL.createObjectURL(file); var objectUrl = URL.createObjectURL(file);
var pdfDocument = await this.toPdfLib(objectUrl); var pdfDocument = await this.toPdfLib(objectUrl);
var renderer = await this.toRenderer(objectUrl); var renderer = await this.toRenderer(objectUrl);
return {renderer, pdfDocument}; return { renderer, pdfDocument };
} }
async toRenderer(objectUrl) { async toRenderer(objectUrl) {
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; pdfjsLib.GlobalWorkerOptions.workerSrc = "./pdfjs-legacy/pdf.worker.mjs";
const pdf = await pdfjsLib.getDocument(objectUrl).promise; const pdf = await pdfjsLib.getDocument(objectUrl).promise;
return { return {
document: pdf, document: pdf,
@@ -298,7 +277,7 @@ class PdfContainer {
renderPage: async function (pageIdx) { renderPage: async function (pageIdx) {
const page = await this.document.getPage(pageIdx + 1); const page = await this.document.getPage(pageIdx + 1);
const canvas = document.createElement('canvas'); const canvas = document.createElement("canvas");
// set the canvas size to the size of the page // set the canvas size to the size of the page
if (page.rotate == 90 || page.rotate == 270) { if (page.rotate == 90 || page.rotate == 270) {
@@ -311,8 +290,8 @@ class PdfContainer {
// render the page onto the canvas // render the page onto the canvas
var renderContext = { var renderContext = {
canvasContext: canvas.getContext('2d'), canvasContext: canvas.getContext("2d"),
viewport: page.getViewport({scale: 1}), viewport: page.getViewport({ scale: 1 }),
}; };
await page.render(renderContext).promise; await page.render(renderContext).promise;
@@ -330,7 +309,6 @@ class PdfContainer {
} }
rotateAll(deg) { rotateAll(deg) {
let elementsToRotate = [];
for (let i = 0; i < this.pagesContainer.childNodes.length; i++) { for (let i = 0; i < this.pagesContainer.childNodes.length; i++) {
const child = this.pagesContainer.children[i]; const child = this.pagesContainer.children[i];
if (!child) continue; if (!child) continue;
@@ -339,53 +317,70 @@ class PdfContainer {
//if in page select mode is active rotate only selected pages //if in page select mode is active rotate only selected pages
if (window.selectPage && !window.selectedPages.includes(pageIndex)) continue; if (window.selectPage && !window.selectedPages.includes(pageIndex)) continue;
const img = child.querySelector('img'); const img = child.querySelector("img");
if (!img) continue; if (!img) continue;
elementsToRotate.push(img); this.rotateElement(img, deg);
}
} }
let rotateAllCommand = new RotateAllCommand(elementsToRotate, deg); removeAllElements(){
rotateAllCommand.execute(); let pageContainerNodeList = document.querySelectorAll(".page-container");
this.undoManager.pushUndoClearRedo(rotateAllCommand);
}
removeAllElements() {
let pageContainerNodeList = document.querySelectorAll('.page-container');
for (var i = 0; i < pageContainerNodeList.length; i++) { for (var i = 0; i < pageContainerNodeList.length; i++) {
pageContainerNodeList[i].remove(); pageContainerNodeList[i].remove();
} }
document.querySelectorAll('.enable-on-file').forEach((element) => { document.querySelectorAll(".enable-on-file").forEach((element) => {
element.disabled = true; element.disabled = true;
}); });
} }
deleteSelected() { deleteSelected() {
window.selectedPages.sort((a, b) => a - b); window.selectedPages.sort((a, b) => a - b);
let removeSelectedCommand = new RemoveSelectedCommand( let deletions = 0;
this.pagesContainer,
window.selectedPages, window.selectedPages.forEach((pageIndex) => {
this.updatePageNumbersAndCheckboxes const adjustedIndex = pageIndex - 1 - deletions;
); const child = this.pagesContainer.children[adjustedIndex];
removeSelectedCommand.execute(); if (child) {
this.undoManager.pushUndoClearRedo(removeSelectedCommand); this.pagesContainer.removeChild(child);
deletions++;
}
});
if (this.pagesContainer.childElementCount === 0) {
const filenameInput = document.getElementById("filename-input");
const filenameParagraph = document.getElementById("filename");
const downloadBtn = document.getElementById("export-button");
if (filenameInput)
filenameInput.disabled = true;
filenameInput.value = "";
if (filenameParagraph)
filenameParagraph.innerText = "";
downloadBtn.disabled = true;
}
window.selectedPages = [];
this.updatePageNumbersAndCheckboxes();
document.dispatchEvent(new Event("selectedPagesUpdated"));
} }
toggleSelectAll() { toggleSelectAll() {
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox'); const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
window.selectAll = !window.selectAll; window.selectAll = !window.selectAll;
const selectIcon = document.getElementById('select-All-Container'); const selectIcon = document.getElementById("select-All-Container");
const deselectIcon = document.getElementById('deselect-All-Container'); const deselectIcon = document.getElementById("deselect-All-Container");
if (selectIcon.style.display === 'none') { if (selectIcon.style.display === "none") {
selectIcon.style.display = 'inline'; selectIcon.style.display = "inline";
deselectIcon.style.display = 'none'; deselectIcon.style.display = "none";
} else { } else {
selectIcon.style.display = 'none'; selectIcon.style.display = "none";
deselectIcon.style.display = 'inline'; deselectIcon.style.display = "inline";
} }
checkboxes.forEach((checkbox) => { checkboxes.forEach((checkbox) => {
checkbox.checked = window.selectAll; checkbox.checked = window.selectAll;
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1; const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
@@ -408,20 +403,18 @@ class PdfContainer {
parseCSVInput(csvInput, maxPageIndex) { parseCSVInput(csvInput, maxPageIndex) {
const pages = new Set(); const pages = new Set();
csvInput.split(',').forEach((item) => { csvInput.split(",").forEach((item) => {
const range = item.split('-').map((p) => parseInt(p.trim())); const range = item.split("-").map((p) => parseInt(p.trim()));
if (range.length === 2) { if (range.length === 2) {
const [start, end] = range; const [start, end] = range;
for (let i = start; i <= end && i <= maxPageIndex; i++) { for (let i = start; i <= end && i <= maxPageIndex; i++) {
if (i > 0) { if (i > 0) { // Ensure the page number is greater than 0
// Ensure the page number is greater than 0
pages.add(i); pages.add(i);
} }
} }
} else if (range.length === 1 && Number.isInteger(range[0])) { } else if (range.length === 1 && Number.isInteger(range[0])) {
const page = range[0]; const page = range[0];
if (page > 0 && page <= maxPageIndex) { if (page > 0 && page <= maxPageIndex) { // Ensure page is within valid range
// Ensure page is within valid range
pages.add(page); pages.add(page);
} }
} }
@@ -431,24 +424,24 @@ class PdfContainer {
} }
updatePagesFromCSV() { updatePagesFromCSV() {
const csvInput = document.getElementById('csv-input').value; const csvInput = document.getElementById("csv-input").value;
const allPages = this.pagesContainer.querySelectorAll('.page-container'); const allPages = this.pagesContainer.querySelectorAll(".page-container");
const maxPageIndex = allPages.length; const maxPageIndex = allPages.length;
window.selectedPages = this.parseCSVInput(csvInput, maxPageIndex); window.selectedPages = this.parseCSVInput(csvInput, maxPageIndex);
this.updateSelectedPagesDisplay(); this.updateSelectedPagesDisplay();
const allCheckboxes = document.querySelectorAll('.pdf-actions_checkbox'); const allCheckboxes = document.querySelectorAll(".pdf-actions_checkbox");
allCheckboxes.forEach((checkbox) => { allCheckboxes.forEach((checkbox) => {
const page = parseInt(checkbox.getAttribute('data-page-number')); const page = parseInt(checkbox.getAttribute("data-page-number"));
checkbox.checked = window.selectedPages.includes(page); checkbox.checked = window.selectedPages.includes(page);
}); });
} }
formatSelectedPages(pages) { formatSelectedPages(pages) {
if (pages.length === 0) return ''; if (pages.length === 0) return "";
pages.sort((a, b) => a - b); // Sort the page numbers in ascending order pages.sort((a, b) => a - b); // Sort the page numbers in ascending order
const ranges = []; const ranges = [];
@@ -469,27 +462,27 @@ class PdfContainer {
// Add the last range // Add the last range
ranges.push(start === end ? `${start}` : `${start}-${end}`); ranges.push(start === end ? `${start}` : `${start}-${end}`);
return ranges.join(', '); return ranges.join(", ");
} }
updateSelectedPagesDisplay() { updateSelectedPagesDisplay() {
const selectedPagesList = document.getElementById('selected-pages-list'); const selectedPagesList = document.getElementById("selected-pages-list");
const selectedPagesInput = document.getElementById('csv-input'); const selectedPagesInput = document.getElementById("csv-input");
selectedPagesList.innerHTML = ''; // Clear the list selectedPagesList.innerHTML = ""; // Clear the list
window.selectedPages.sort((a, b) => a - b); window.selectedPages.sort((a, b) => a - b);
window.selectedPages.forEach((page) => { window.selectedPages.forEach((page) => {
const pageItem = document.createElement('div'); const pageItem = document.createElement("div");
pageItem.className = 'page-item'; pageItem.className = "page-item";
const pageNumber = document.createElement('span'); const pageNumber = document.createElement("span");
const pagelabel = /*[[#{multiTool.page}]]*/ 'Page'; const pagelabel = /*[[#{multiTool.page}]]*/ 'Page';
pageNumber.className = 'selected-page-number'; pageNumber.className = "selected-page-number";
pageNumber.innerText = `${pagelabel} ${page}`; pageNumber.innerText = `${pagelabel} ${page}`;
pageItem.appendChild(pageNumber); pageItem.appendChild(pageNumber);
const removeBtn = document.createElement('span'); const removeBtn = document.createElement("span");
removeBtn.className = 'remove-btn'; removeBtn.className = "remove-btn";
removeBtn.innerHTML = '✕'; removeBtn.innerHTML = "✕";
// Remove page from selected pages list and update display and checkbox // Remove page from selected pages list and update display and checkbox
removeBtn.onclick = () => { removeBtn.onclick = () => {
@@ -513,7 +506,7 @@ class PdfContainer {
parsePageRanges(ranges) { parsePageRanges(ranges) {
const pages = new Set(); const pages = new Set();
ranges.split(',').forEach((range) => { ranges.split(',').forEach(range => {
const [start, end] = range.split('-').map(Number); const [start, end] = range.split('-').map(Number);
if (end) { if (end) {
for (let i = start; i <= end; i++) { for (let i = start; i <= end; i++) {
@@ -527,35 +520,50 @@ class PdfContainer {
return Array.from(pages).sort((a, b) => a - b); return Array.from(pages).sort((a, b) => a - b);
} }
async addFilesBlankAll() { addFilesBlankAll() {
const allPages = this.pagesContainer.querySelectorAll('.page-container'); const allPages = this.pagesContainer.querySelectorAll(".page-container");
allPages.forEach((page, index) => {
let pageBreakCommand = new PageBreakCommand( if (index !== 0) {
allPages, this.addFiles(page, true)
window.selectPage, }
window.selectedPages, });
this.addFilesBlank.bind(this),
this.pagesContainer
);
await pageBreakCommand.execute();
this.undoManager.pushUndoClearRedo(pageBreakCommand);
} }
splitAll() { splitAll() {
const allPages = this.pagesContainer.querySelectorAll('.page-container'); const allPages = this.pagesContainer.querySelectorAll(".page-container");
let splitAllCommand = new SplitAllCommand(allPages, window.selectPage, window.selectedPages, 'split-before');
splitAllCommand.execute();
this.undoManager.pushUndoClearRedo(splitAllCommand); if (!window.selectPage) {
const hasSplit = this.pagesContainer.querySelectorAll(".split-before").length > 0;
if (hasSplit) {
allPages.forEach(page => {
page.classList.remove("split-before");
});
} else {
allPages.forEach(page => {
page.classList.add("split-before");
});
} }
return;
}
allPages.forEach((page, index) => {
const pageIndex = index;
if (window.selectPage && !window.selectedPages.includes(pageIndex)) return;
if (page.classList.contains("split-before")) {
page.classList.remove("split-before");
} else {
page.classList.add("split-before");
}
});
}
async splitPDF(baseDocBytes, splitters) { async splitPDF(baseDocBytes, splitters) {
const baseDocument = await PDFLib.PDFDocument.load(baseDocBytes); const baseDocument = await PDFLib.PDFDocument.load(baseDocBytes);
const pageNum = baseDocument.getPages().length; const pageNum = baseDocument.getPages().length;
splitters.sort((a, b) => a - b); // We'll sort the separator indexes just in case querySelectorAll does something funny. splitters.sort((a, b) => a - b);; // We'll sort the separator indexes just in case querySelectorAll does something funny.
splitters.push(pageNum); // We'll also add a faux separator at the end in order to get the pages after the last separator. splitters.push(pageNum); // We'll also add a faux separator at the end in order to get the pages after the last separator.
const splitDocuments = []; const splitDocuments = [];
@@ -566,18 +574,18 @@ class PdfContainer {
let firstPage = splitterIndex === 0 ? 0 : splitters[splitterIndex - 1]; let firstPage = splitterIndex === 0 ? 0 : splitters[splitterIndex - 1];
const pageIndices = Array.from({length: splitterPosition - firstPage}, (value, key) => firstPage + key); const pageIndices = Array.from({ length: splitterPosition - firstPage }, (value, key) => firstPage + key);
const copiedPages = await subDocument.copyPages(baseDocument, pageIndices); const copiedPages = await subDocument.copyPages(baseDocument, pageIndices);
copiedPages.forEach((copiedPage) => { copiedPages.forEach(copiedPage => {
subDocument.addPage(copiedPage); subDocument.addPage(copiedPage);
}); });
const subDocumentBytes = await subDocument.save(); const subDocumentBytes = await subDocument.save();
splitDocuments.push(subDocumentBytes); splitDocuments.push(subDocumentBytes);
} };
return splitDocuments; return splitDocuments;
} }
@@ -586,10 +594,8 @@ class PdfContainer {
const zip = new JSZip(); const zip = new JSZip();
for (let i = 0; i < pdfBytesArray.length; i++) { for (let i = 0; i < pdfBytesArray.length; i++) {
const documentBlob = new Blob([pdfBytesArray[i]], { const documentBlob = new Blob([pdfBytesArray[i]], { type: "application/pdf" });
type: 'application/pdf', zip.file(baseNameString + "-" + (i + 1) + ".pdf", documentBlob);
});
zip.file(baseNameString + '-' + (i + 1) + '.pdf', documentBlob);
} }
return zip; return zip;
@@ -597,10 +603,10 @@ class PdfContainer {
async exportPdf(selected) { async exportPdf(selected) {
const pdfDoc = await PDFLib.PDFDocument.create(); const pdfDoc = await PDFLib.PDFDocument.create();
const pageContainers = this.pagesContainer.querySelectorAll('.page-container'); // Select all .page-container elements const pageContainers = this.pagesContainer.querySelectorAll(".page-container"); // Select all .page-container elements
for (var i = 0; i < pageContainers.length; i++) { for (var i = 0; i < pageContainers.length; i++) {
if (!selected || window.selectedPages.includes(i + 1)) { if (!selected || window.selectedPages.includes(i + 1)) {
const img = pageContainers[i].querySelector('img'); // Find the img element within each .page-container const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container
if (!img) continue; if (!img) continue;
let page; let page;
if (img.doc) { if (img.doc) {
@@ -640,7 +646,7 @@ class PdfContainer {
} }
const rotation = img.style.rotate; const rotation = img.style.rotate;
if (rotation) { if (rotation) {
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, '')); const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, ""));
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle)); page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
} }
} }
@@ -649,11 +655,11 @@ class PdfContainer {
pdfDoc.setProducer(stirlingPDFLabel); pdfDoc.setProducer(stirlingPDFLabel);
const pdfBytes = await pdfDoc.save(); const pdfBytes = await pdfDoc.save();
const pdfBlob = new Blob([pdfBytes], {type: 'application/pdf'}); const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" });
const filenameInput = document.getElementById('filename-input'); const filenameInput = document.getElementById("filename-input");
let inputArr = filenameInput.value.split('.'); let inputArr = filenameInput.value.split(".");
if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) { if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) {
inputArr = inputArr.filter((n) => n); // remove all empty strings, nulls or undefined inputArr = inputArr.filter((n) => n); // remove all empty strings, nulls or undefined
@@ -662,18 +668,17 @@ class PdfContainer {
inputArr.pop(); // remove right part after last dot inputArr.pop(); // remove right part after last dot
} }
filenameInput.value = inputArr.join(''); filenameInput.value = inputArr.join("");
this.fileName = filenameInput.value; this.fileName = filenameInput.value;
} }
const separators = this.pagesContainer.querySelectorAll('.split-before'); const separators = this.pagesContainer.querySelectorAll(".split-before");
if (separators.length !== 0) { if (separators.length !== 0) { // Split the pdf if there are separators.
// Split the pdf if there are separators. const baseName = this.fileName ? this.fileName : "managed";
const baseName = this.fileName ? this.fileName : 'managed';
const pagesArray = Array.from(this.pagesContainer.children); const pagesArray = Array.from(this.pagesContainer.children);
const splitters = []; const splitters = [];
separators.forEach((page) => { separators.forEach(page => {
const pageIndex = pagesArray.indexOf(page); const pageIndex = pagesArray.indexOf(page);
if (pageIndex !== 0) { if (pageIndex !== 0) {
splitters.push(pageIndex); splitters.push(pageIndex);
@@ -684,40 +689,40 @@ class PdfContainer {
const archivedDocuments = await this.nameAndArchiveFiles(splitDocuments, baseName); const archivedDocuments = await this.nameAndArchiveFiles(splitDocuments, baseName);
const self = this; const self = this;
archivedDocuments.generateAsync({type: 'base64'}).then(function (base64) { archivedDocuments.generateAsync({ type: "base64" }).then(function (base64) {
const url = 'data:application/zip;base64,' + base64; const url = "data:application/zip;base64," + base64;
self.downloadLink = document.createElement('a'); self.downloadLink = document.createElement("a");
self.downloadLink.href = url; self.downloadLink.href = url;
self.downloadLink.setAttribute('download', baseName + '.zip'); self.downloadLink.setAttribute("download", baseName + ".zip");
self.downloadLink.setAttribute('target', '_blank'); self.downloadLink.setAttribute("target", "_blank");
self.downloadLink.click(); self.downloadLink.click();
}); });
} else {
// Continue normally if there are no separators } else { // Continue normally if there are no separators
const url = URL.createObjectURL(pdfBlob); const url = URL.createObjectURL(pdfBlob);
const downloadOption = localStorage.getItem('downloadOption'); const downloadOption = localStorage.getItem("downloadOption");
if (!filenameInput.value.includes('.pdf')) { if (!filenameInput.value.includes(".pdf")) {
filenameInput.value = filenameInput.value + '.pdf'; filenameInput.value = filenameInput.value + ".pdf";
this.fileName = filenameInput.value; this.fileName = filenameInput.value;
} }
if (downloadOption === 'sameWindow') { if (downloadOption === "sameWindow") {
// Open the file in the same window // Open the file in the same window
window.location.href = url; window.location.href = url;
} else if (downloadOption === 'newWindow') { } else if (downloadOption === "newWindow") {
// Open the file in a new window // Open the file in a new window
window.open(url, '_blank'); window.open(url, "_blank");
} else { } else {
// Download the file // Download the file
this.downloadLink = document.createElement('a'); this.downloadLink = document.createElement("a");
this.downloadLink.id = 'download-link'; this.downloadLink.id = "download-link";
this.downloadLink.href = url; this.downloadLink.href = url;
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf'; // downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
// downloadLink.download = this.fileName; // downloadLink.download = this.fileName;
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf'); this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
this.downloadLink.setAttribute('target', '_blank'); this.downloadLink.setAttribute("target", "_blank");
this.downloadLink.onclick = this.setDownloadAttribute; this.downloadLink.onclick = this.setDownloadAttribute;
this.downloadLink.click(); this.downloadLink.click();
} }
@@ -725,19 +730,19 @@ class PdfContainer {
} }
resetPages() { resetPages() {
const pageContainers = this.pagesContainer.querySelectorAll('.page-container'); const pageContainers = this.pagesContainer.querySelectorAll(".page-container");
pageContainers.forEach((container, index) => { pageContainers.forEach((container, index) => {
container.id = 'page-container-' + (index + 1); container.id = "page-container-" + (index + 1);
}); });
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox'); const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
window.selectAll = false; window.selectAll = false;
const selectIcon = document.getElementById('select-All-Container'); const selectIcon = document.getElementById("select-All-Container");
const deselectIcon = document.getElementById('deselect-All-Container'); const deselectIcon = document.getElementById("deselect-All-Container");
selectIcon.style.display = 'inline'; selectIcon.style.display = "inline";
deselectIcon.style.display = 'none'; deselectIcon.style.display = "none";
checkboxes.forEach((checkbox) => { checkboxes.forEach((checkbox) => {
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1; const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
@@ -751,13 +756,13 @@ class PdfContainer {
} }
setDownloadAttribute() { setDownloadAttribute() {
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf'); this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
} }
updateFilename(fileName = '') { updateFilename(fileName = "") {
const filenameInput = document.getElementById('filename-input'); const filenameInput = document.getElementById("filename-input");
const pagesContainer = document.getElementById('pages-container'); const pagesContainer = document.getElementById("pages-container");
const downloadBtn = document.getElementById('export-button'); const downloadBtn = document.getElementById("export-button");
downloadBtn.disabled = pagesContainer.childElementCount === 0; downloadBtn.disabled = pagesContainer.childElementCount === 0;
@@ -781,36 +786,38 @@ class PdfContainer {
// } // }
} }
toggleSelectPageVisibility() { toggleSelectPageVisibility() {
window.selectPage = !window.selectPage; window.selectPage = !window.selectPage;
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox'); const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
checkboxes.forEach((checkbox) => { checkboxes.forEach(checkbox => {
checkbox.classList.toggle('hidden', !window.selectPage); checkbox.classList.toggle("hidden", !window.selectPage);
}); });
const deleteButton = document.getElementById('delete-button'); const deleteButton = document.getElementById("delete-button");
deleteButton.classList.toggle('hidden', !window.selectPage); deleteButton.classList.toggle("hidden", !window.selectPage);
const selectedPages = document.getElementById('selected-pages-display'); const selectedPages = document.getElementById("selected-pages-display");
selectedPages.classList.toggle('hidden', !window.selectPage); selectedPages.classList.toggle("hidden", !window.selectPage);
const selectAll = document.getElementById('select-All-Container'); const selectAll = document.getElementById("select-All-Container");
selectAll.classList.toggle('hidden', !window.selectPage); selectAll.classList.toggle("hidden", !window.selectPage);
const exportSelected = document.getElementById('export-selected-button'); const exportSelected = document.getElementById("export-selected-button");
exportSelected.classList.toggle('hidden', !window.selectPage); exportSelected.classList.toggle("hidden", !window.selectPage);
const selectPagesButton = document.getElementById('select-pages-button'); const selectPagesButton = document.getElementById("select-pages-button");
selectPagesButton.style.opacity = window.selectPage ? '1' : '0.5'; selectPagesButton.style.opacity = window.selectPage ? "1" : "0.5";
if (window.selectPage) { if (window.selectPage) {
this.updatePageNumbersAndCheckboxes(); this.updatePageNumbersAndCheckboxes();
} }
} }
updatePageNumbersAndCheckboxes() { updatePageNumbersAndCheckboxes() {
const pageDivs = document.querySelectorAll('.pdf-actions_container'); const pageDivs = document.querySelectorAll(".pdf-actions_container");
pageDivs.forEach((div, index) => { pageDivs.forEach((div, index) => {
const pageNumber = index + 1; const pageNumber = index + 1;
const checkbox = div.querySelector('.pdf-actions_checkbox'); const checkbox = div.querySelector(".pdf-actions_checkbox");
checkbox.id = `selectPageCheckbox-${pageNumber}`; checkbox.id = `selectPageCheckbox-${pageNumber}`;
checkbox.setAttribute('data-page-number', pageNumber); checkbox.setAttribute("data-page-number", pageNumber);
checkbox.checked = window.selectedPages.includes(pageNumber); checkbox.checked = window.selectedPages.includes(pageNumber);
}); });
} }
@@ -828,10 +835,8 @@ function detectImageType(uint8Array) {
} }
// Check for TIFF signature (little-endian and big-endian) // Check for TIFF signature (little-endian and big-endian)
if ( if ((uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) ||
(uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) || (uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)) {
(uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)
) {
return 'TIFF'; return 'TIFF';
} }
@@ -843,4 +848,6 @@ function detectImageType(uint8Array) {
return 'UNKNOWN'; return 'UNKNOWN';
} }
export default PdfContainer; export default PdfContainer;

View File

@@ -1,65 +0,0 @@
export class UndoManager {
_undoStack;
_redoStack;
constructor() {
this._undoStack = [];
this._redoStack = [];
}
pushUndo(command) {
this._undoStack.push(command);
this._dispatchStateChange();
}
pushRedo(command) {
this._redoStack.push(command);
this._dispatchStateChange();
}
pushUndoClearRedo(command) {
this._undoStack.push(command);
this._redoStack = [];
this._dispatchStateChange();
}
undo() {
if (!this.canUndo()) return;
let cmd = this._undoStack.pop();
cmd.undo();
this._redoStack.push(cmd);
this._dispatchStateChange();
}
canUndo() {
return this._undoStack && this._undoStack.length > 0;
}
redo() {
if (!this.canRedo()) return;
let cmd = this._redoStack.pop();
cmd.redo();
this._undoStack.push(cmd);
this._dispatchStateChange();
}
canRedo() {
return this._redoStack && this._redoStack.length > 0;
}
_dispatchStateChange() {
document.dispatchEvent(
new CustomEvent("undo-manager-update", {
bubbles: true,
detail: {
canUndo: this.canUndo(),
canRedo: this.canRedo(),
},
})
);
}
}

View File

@@ -1,53 +0,0 @@
import {Command} from './command.js';
export class AddFilesCommand extends Command {
constructor(element, selectedPages, addFilesAction, pagesContainer) {
super();
this.element = element;
this.selectedPages = selectedPages;
this.addFilesAction = addFilesAction;
this.pagesContainer = pagesContainer;
this.addedElements = [];
}
async execute() {
const undoBtn = document.getElementById('undo-btn');
undoBtn.disabled = true;
if (this.element) {
const newElement = await this.addFilesAction(this.element);
if (newElement) {
this.addedElements = newElement;
}
} else {
const newElement = await this.addFilesAction(false);
if (newElement) {
this.addedElements = newElement;
}
}
undoBtn.disabled = false;
}
undo() {
this.addedElements.forEach((element) => {
const nextSibling = element.nextSibling;
this.pagesContainer.removeChild(element);
if (this.pagesContainer.childElementCount === 0) {
const filenameInput = document.getElementById('filename-input');
const filenameParagraph = document.getElementById('filename');
const downloadBtn = document.getElementById('export-button');
filenameInput.disabled = true;
filenameInput.value = '';
filenameParagraph.innerText = '';
downloadBtn.disabled = true;
}
element._nextSibling = nextSibling;
});
this.addedElements = [];
}
redo() {
this.execute();
}
}

View File

@@ -1,5 +0,0 @@
export class Command {
execute() {}
undo() {}
redo() {}
}

View File

@@ -1,76 +0,0 @@
import { Command } from "./command.js";
export class DeletePageCommand extends Command {
constructor(element, pagesContainer) {
super();
this.element = element;
this.pagesContainer = pagesContainer;
this.filenameInputValue = document.getElementById("filename-input").value;
const filenameParagraph = document.getElementById("filename");
this.filenameParagraphText = filenameParagraph
? filenameParagraph.innerText
: "";
}
execute() {
this.nextSibling = this.element.nextSibling;
this.pagesContainer.removeChild(this.element);
if (this.pagesContainer.childElementCount === 0) {
const filenameInput = document.getElementById("filename-input");
const filenameParagraph = document.getElementById("filename");
const downloadBtn = document.getElementById("export-button");
filenameInput.disabled = true;
filenameInput.value = "";
filenameParagraph.innerText = "";
downloadBtn.disabled = true;
}
}
undo() {
let node = this.nextSibling;
if (node) this.pagesContainer.insertBefore(this.element, node);
else this.pagesContainer.appendChild(this.element);
const pageNumberElement = this.element.querySelector(".page-number");
if (pageNumberElement) {
this.element.removeChild(pageNumberElement);
}
const filenameInput = document.getElementById("filename-input");
const filenameParagraph = document.getElementById("filename");
const downloadBtn = document.getElementById("export-button");
filenameInput.disabled = false;
filenameInput.value = this.filenameInputValue;
if (this.filenameParagraph)
filenameParagraph.innerText = this.filenameParagraphText;
downloadBtn.disabled = false;
}
redo() {
const pageNumberElement = this.element.querySelector(".page-number");
if (pageNumberElement) {
this.element.removeChild(pageNumberElement);
}
this.pagesContainer.removeChild(this.element);
if (this.pagesContainer.childElementCount === 0) {
const filenameInput = document.getElementById("filename-input");
const filenameParagraph = document.getElementById("filename");
const downloadBtn = document.getElementById("export-button");
filenameInput.disabled = true;
filenameInput.value = "";
filenameParagraph.innerText = "";
downloadBtn.disabled = true;
}
}
}

View File

@@ -1,133 +0,0 @@
import { Command } from "./command.js";
export class AbstractMovePageCommand extends Command {
constructor(
startElement,
endElement,
pagesContainer,
pagesContainerWrapper,
scrollTo = false
) {
super();
this.pagesContainer = pagesContainer;
const childArray = Array.from(this.pagesContainer.childNodes);
this.startIndex = childArray.indexOf(startElement);
this.endIndex = childArray.indexOf(endElement);
this.startElement = startElement;
this.endElement = endElement;
this.scrollTo = scrollTo;
this.pagesContainerWrapper = pagesContainerWrapper;
}
execute() {
// Check & remove page number elements here too if they exist because Firefox doesn't fire the relevant event on page move.
const pageNumberElement = this.startElement.querySelector(".page-number");
if (pageNumberElement) {
this.startElement.removeChild(pageNumberElement);
}
this.pagesContainer.removeChild(this.startElement);
if (!this.endElement) {
this.pagesContainer.append(this.startElement);
} else {
this.pagesContainer.insertBefore(this.startElement, this.endElement);
}
if (this.scrollTo) {
const { width } = this.startElement.getBoundingClientRect();
const vector =
this.endIndex !== -1 && this.startIndex > this.endIndex
? 0 - width
: width;
this.pagesContainerWrapper.scroll({
left: this.pagesContainerWrapper.scrollLeft + vector,
});
}
}
undo() {
// Requires overriding in child classes
}
redo() {
this.execute();
}
}
export class MovePageUpCommand extends AbstractMovePageCommand {
constructor(
startElement,
endElement,
pagesContainer,
pagesContainerWrapper,
scrollTo = false
) {
super(startElement, endElement, pagesContainer, pagesContainerWrapper, scrollTo);
}
undo() {
if (this.endElement) {
this.pagesContainer.removeChild(this.endElement);
this.startElement.insertAdjacentElement("beforebegin", this.endElement);
}
if (this.scrollTo) {
const { width } = this.startElement.getBoundingClientRect();
const vector =
this.endIndex === -1 || this.startIndex <= this.endIndex
? 0 - width
: width;
this.pagesContainerWrapper.scroll({
left: this.pagesContainerWrapper.scrollLeft - vector,
});
}
}
redo() {
this.execute();
}
}
export class MovePageDownCommand extends AbstractMovePageCommand {
constructor(
startElement,
endElement,
pagesContainer,
pagesContainerWrapper,
scrollTo = false
) {
super(startElement, endElement, pagesContainer, pagesContainerWrapper, scrollTo);
}
undo() {
let previousElement = this.startElement.previousSibling;
if (this.startElement) {
this.pagesContainer.removeChild(this.startElement);
previousElement.insertAdjacentElement("beforebegin", this.startElement);
}
if (this.scrollTo) {
const { width } = this.startElement.getBoundingClientRect();
const vector =
this.endIndex === -1 || this.startIndex <= this.endIndex
? 0 - width
: width;
this.pagesContainerWrapper.scroll({
left: this.pagesContainerWrapper.scrollLeft - vector,
});
}
}
redo() {
this.execute();
}
}

View File

@@ -1,59 +0,0 @@
import {Command} from './command.js';
export class PageBreakCommand extends Command {
constructor(elements, isSelectedInWindow, selectedPages, pageBreakCallback, pagesContainer) {
super();
this.elements = elements;
this.isSelectedInWindow = isSelectedInWindow;
this.selectedPages = selectedPages;
this.pageBreakCallback = pageBreakCallback;
this.pagesContainer = pagesContainer;
this.addedElements = [];
this.originalStates = Array.from(elements, (element) => ({
element,
hasContent: element.innerHTML.trim() !== '',
}));
}
async execute() {
const undoBtn = document.getElementById('undo-btn');
undoBtn.disabled = true;
for (const [index, element] of this.elements.entries()) {
if (!this.isSelectedInWindow || this.selectedPages.includes(index)) {
if (index !== 0) {
const newElement = await this.pageBreakCallback(element, this.addedElements);
if (newElement) {
this.addedElements = newElement;
}
}
}
}
undoBtn.disabled = false;
}
undo() {
this.addedElements.forEach((element) => {
const nextSibling = element.nextSibling;
this.pagesContainer.removeChild(element);
if (this.pagesContainer.childElementCount === 0) {
const filenameInput = document.getElementById('filename-input');
const filenameParagraph = document.getElementById('filename');
const downloadBtn = document.getElementById('export-button');
filenameInput.disabled = true;
filenameInput.value = '';
filenameParagraph.innerText = '';
downloadBtn.disabled = true;
}
element._nextSibling = nextSibling;
});
}
redo() {
this.execute();
}
}

View File

@@ -1,101 +0,0 @@
import { Command } from "./command.js";
export class RemoveSelectedCommand extends Command {
constructor(pagesContainer, selectedPages, updatePageNumbersAndCheckboxes) {
super();
this.pagesContainer = pagesContainer;
this.selectedPages = selectedPages;
this.deletedChildren = [];
if (updatePageNumbersAndCheckboxes) {
this.updatePageNumbersAndCheckboxes = updatePageNumbersAndCheckboxes;
} else {
const pageDivs = document.querySelectorAll(".pdf-actions_container");
pageDivs.forEach((div, index) => {
const pageNumber = index + 1;
const checkbox = div.querySelector(".pdf-actions_checkbox");
checkbox.id = `selectPageCheckbox-${pageNumber}`;
checkbox.setAttribute("data-page-number", pageNumber);
checkbox.checked = window.selectedPages.includes(pageNumber);
});
}
const filenameInput = document.getElementById("filename-input");
const filenameParagraph = document.getElementById("filename");
this.originalFilenameInputValue = filenameInput ? filenameInput.value : "";
if (filenameParagraph)
this.originalFilenameParagraphText = filenameParagraph.innerText;
}
execute() {
let deletions = 0;
this.selectedPages.forEach((pageIndex) => {
const adjustedIndex = pageIndex - 1 - deletions;
const child = this.pagesContainer.children[adjustedIndex];
if (child) {
this.pagesContainer.removeChild(child);
deletions++;
this.deletedChildren.push({
idx: adjustedIndex,
childNode: child,
});
}
});
if (this.pagesContainer.childElementCount === 0) {
const filenameInput = document.getElementById("filename-input");
const filenameParagraph = document.getElementById("filename");
const downloadBtn = document.getElementById("export-button");
if (filenameInput) filenameInput.disabled = true;
filenameInput.value = "";
if (filenameParagraph) filenameParagraph.innerText = "";
downloadBtn.disabled = true;
}
window.selectedPages = [];
this.updatePageNumbersAndCheckboxes();
document.dispatchEvent(new Event("selectedPagesUpdated"));
}
undo() {
while (this.deletedChildren.length > 0) {
let deletedChild = this.deletedChildren.pop();
if (this.pagesContainer.children.length <= deletedChild.idx)
this.pagesContainer.appendChild(deletedChild.childNode);
else {
this.pagesContainer.insertBefore(
deletedChild.childNode,
this.pagesContainer.children[deletedChild.idx]
);
}
}
if (this.pagesContainer.childElementCount > 0) {
const filenameInput = document.getElementById("filename-input");
const filenameParagraph = document.getElementById("filename");
const downloadBtn = document.getElementById("export-button");
if (filenameInput) filenameInput.disabled = false;
filenameInput.value = this.originalFilenameInputValue;
if (filenameParagraph)
filenameParagraph.innerText = this.originalFilenameParagraphText;
downloadBtn.disabled = false;
}
window.selectedPages = this.selectedPages;
this.updatePageNumbersAndCheckboxes();
document.dispatchEvent(new Event("selectedPagesUpdated"));
}
redo() {
this.execute();
}
}

View File

@@ -1,74 +0,0 @@
import { Command } from "./command.js";
export class RotateElementCommand extends Command {
constructor(element, degree) {
super();
this.element = element;
this.degree = degree;
}
execute() {
let lastTransform = this.element.style.rotate;
if (!lastTransform) {
lastTransform = "0";
}
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
const newAngle = lastAngle + parseInt(this.degree);
this.element.style.rotate = newAngle + "deg";
}
undo() {
let lastTransform = this.element.style.rotate;
if (!lastTransform) {
lastTransform = "0";
}
const currentAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
const undoAngle = currentAngle + -parseInt(this.degree);
this.element.style.rotate = undoAngle + "deg";
}
redo() {
this.execute();
}
}
export class RotateAllCommand extends Command {
constructor(elements, degree) {
super();
this.elements = elements;
this.degree = degree;
}
execute() {
for (let element of this.elements) {
let lastTransform = element.style.rotate;
if (!lastTransform) {
lastTransform = "0";
}
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
const newAngle = lastAngle + this.degree;
element.style.rotate = newAngle + "deg";
}
}
undo() {
for (let element of this.elements) {
let lastTransform = element.style.rotate;
if (!lastTransform) {
lastTransform = "0";
}
const currentAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
const undoAngle = currentAngle + -this.degree;
element.style.rotate = undoAngle + "deg";
}
}
redo() {
this.execute();
}
}

View File

@@ -1,59 +0,0 @@
import { Command } from "./command.js";
export class SelectPageCommand extends Command {
constructor(pageNumber, checkbox) {
super();
this.pageNumber = pageNumber;
this.selectCheckbox = checkbox;
}
execute() {
if (this.selectCheckbox.checked) {
//adds to array of selected pages
window.selectedPages.push(this.pageNumber);
} else {
//remove page from selected pages array
const index = window.selectedPages.indexOf(this.pageNumber);
if (index !== -1) {
window.selectedPages.splice(index, 1);
}
}
if (window.selectedPages.length > 0 && !window.selectPage) {
window.toggleSelectPageVisibility();
}
if (window.selectedPages.length == 0 && window.selectPage) {
window.toggleSelectPageVisibility();
}
window.updateSelectedPagesDisplay();
}
undo() {
this.selectCheckbox.checked = !this.selectCheckbox.checked;
if (this.selectCheckbox.checked) {
//adds to array of selected pages
window.selectedPages.push(this.pageNumber);
} else {
//remove page from selected pages array
const index = window.selectedPages.indexOf(this.pageNumber);
if (index !== -1) {
window.selectedPages.splice(index, 1);
}
}
if (window.selectedPages.length > 0 && !window.selectPage) {
window.toggleSelectPageVisibility();
}
if (window.selectedPages.length == 0 && window.selectPage) {
window.toggleSelectPageVisibility();
}
window.updateSelectedPagesDisplay();
}
redo() {
this.selectCheckbox.checked = !this.selectCheckbox.checked;
this.execute();
}
}

View File

@@ -1,101 +0,0 @@
import { Command } from "./command.js";
export class SplitFileCommand extends Command {
constructor(element, splitClass) {
super();
this.element = element;
this.splitClass = splitClass;
}
execute() {
this.element.classList.toggle(this.splitClass);
}
undo() {
this.element.classList.toggle(this.splitClass);
}
redo() {
this.execute();
}
}
export class SplitAllCommand extends Command {
constructor(elements, isSelectedInWindow, selectedPages, splitClass) {
super();
this.elements = elements;
this.isSelectedInWindow = isSelectedInWindow;
this.selectedPages = selectedPages;
this.splitClass = splitClass;
}
execute() {
if (!this.isSelectedInWindow) {
const hasSplit = this._hasSplit(this.elements, this.splitClass);
if (hasSplit) {
this.elements.forEach((page) => {
page.classList.remove(this.splitClass);
});
} else {
this.elements.forEach((page) => {
page.classList.add(this.splitClass);
});
}
return;
}
this.elements.forEach((page, index) => {
const pageIndex = index;
if (this.isSelectedInWindow && !this.selectedPages.includes(pageIndex))
return;
if (page.classList.contains(this.splitClass)) {
page.classList.remove(this.splitClass);
} else {
page.classList.add(this.splitClass);
}
});
}
_hasSplit() {
if (!this.elements || this.elements.length == 0) return false;
for (const node of this.elements) {
if (node.classList.contains(this.splitClass)) return true;
}
return false;
}
undo() {
if (!this.isSelectedInWindow) {
const hasSplit = this._hasSplit(this.elements, this.splitClass);
if (hasSplit) {
this.elements.forEach((page) => {
page.classList.remove(this.splitClass);
});
} else {
this.elements.forEach((page) => {
page.classList.add(this.splitClass);
});
}
return;
}
this.elements.forEach((page, index) => {
const pageIndex = index;
if (this.isSelectedInWindow && !this.selectedPages.includes(pageIndex))
return;
if (page.classList.contains(this.splitClass)) {
page.classList.remove(this.splitClass);
} else {
page.classList.add(this.splitClass);
}
});
}
redo() {
this.execute();
}
}

View File

@@ -1,9 +0,0 @@
class UUID {
static uuidv4() {
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
(+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16)
);
}
}
export default UUID;

View File

@@ -189,7 +189,7 @@
<label for="authType">Authentication Type</label> <label for="authType">Authentication Type</label>
<select id="authType" name="authType" class="form-control" required> <select id="authType" name="authType" class="form-control" required>
<option value="web" selected>WEB</option> <option value="web" selected>WEB</option>
<option value="sso">SSO</option> <option value="oauth2">OAUTH2</option>
</select> </select>
</div> </div>
<div class="form-check mb-3" id="checkboxContainer"> <div class="form-check mb-3" id="checkboxContainer">
@@ -267,7 +267,7 @@
var passwordFieldContainer = $('#passwordContainer'); var passwordFieldContainer = $('#passwordContainer');
var checkboxContainer = $('#checkboxContainer'); var checkboxContainer = $('#checkboxContainer');
if (authType === 'sso') { if (authType === 'oauth2') {
passwordField.removeAttr('required'); passwordField.removeAttr('required');
passwordField.prop('disabled', true).val(''); passwordField.prop('disabled', true).val('');
passwordFieldContainer.slideUp('fast'); passwordFieldContainer.slideUp('fast');

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