Compare commits

...

34 Commits

Author SHA1 Message Date
Anthony Stirling
d19d87b8f0 Update downloader.js 2024-11-20 10:23:29 +00:00
Anthony Stirling
a22ce69bc3 Merge branch 'main' into Frooodle-patch-7 2024-11-20 10:16:44 +00:00
Anthony Stirling
59b60ebfb8 Update common.html 2024-11-20 10:15:23 +00:00
Anthony Stirling
a6ae3734ca Frooodle patch 8 (#2275)
* Update check_properties.yml

* Update messages_en_GB.properties

* Update messages_en_GB.properties
2024-11-20 09:44:51 +00:00
Anthony Stirling
b9a014b5c7 Update downloader.js 2024-11-20 09:23:41 +00:00
Anthony Stirling
9e30918aae Update downloader.js 2024-11-20 09:04:00 +00:00
Anthony Stirling
c239d95131 Update PR-Demo-cleanup.yml 2024-11-20 08:41:29 +00:00
Anthony Stirling
d591874da6 Update PR-Demo-cleanup.yml 2024-11-20 08:28:51 +00:00
Anthony Stirling
6c623d8d84 Update MetricsAggregatorService.java (#2272) 2024-11-20 08:20:01 +00:00
Rafael Encinas
e059caa14e Fix id typo for "cropPdfCanvas" querySelector (#2271)
Fix id typo
2024-11-20 07:53:14 +00:00
dependabot[bot]
8eab35761d Bump org.projectlombok:lombok from 1.18.34 to 1.18.36 (#2266)
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.34 to 1.18.36.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.34...v1.18.36)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 23:16:31 +00:00
Anthony Stirling
c43af24ffe Update PR-Demo-Comment.yml 2024-11-17 16:17:44 +00:00
Anthony Stirling
e1b3cc736c Update PR-Demo-Comment.yml 2024-11-17 15:54:50 +00:00
Anthony Stirling
0fb9e18636 Update PR-Demo-Comment.yml 2024-11-17 15:53:29 +00:00
Ludy
5e1aac0b84 Read login data from application.properties (#2263)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-11-17 14:08:41 +00:00
Anthony Stirling
60bf649260 Update and rename PR-Demos.yml to PR-Demo-cleanup.yml 2024-11-17 13:43:48 +00:00
Anthony Stirling
a58696a38e Create PR-Demo-Comment.yml (#2261)
* Create PR-Demo-Comment.yml

* Update PR-Demo-Comment.yml
2024-11-17 13:32:14 +00:00
Ludy
44abc67678 shows the titles of the buttons (#2262)
* shows the titles of the buttons

* Update navbar.css
2024-11-17 12:33:41 +00:00
Anthony Stirling
d1e690ff8d Update PR-Demos.yml 2024-11-17 10:13:59 +00:00
Anthony Stirling
5dc8fa08ee Create PR-Demos.yml (#2260)
* Create PR-Demos.yml

* Update build.gradle

* Update build.gradle

* Update PR-Demos.yml

* Update PR-Demos.yml

* Update PR-Demos.yml

* Update PR-Demos.yml

* Update PR-Demos.yml

* Update PR-Demos.yml

* Update PR-Demos.yml

* Update PR-Demos.yml

* Update PR-Demos.yml
2024-11-16 22:24:00 +00:00
Anthony Stirling
db028dfe27 docker move 2024-11-16 11:31:26 +00:00
Anthony Stirling
c24c504350 Delete Jenkinsfile 2024-11-16 11:22:17 +00:00
Anthony Stirling
5dcfe64d1c Update README.md 2024-11-16 11:11:12 +00:00
Anthony Stirling
d843696703 Update README.md 2024-11-16 11:07:54 +00:00
Dimitris Kaitantzidis
67de8a9460 Fix canvas pdf to csv (#2228)
* WIP: fixes canvas and rect to crop - small problem in smaller screens - neew to fix re render page on resize

* Closes #2209

* Closes #2227
2024-11-16 11:02:20 +00:00
Anthony Stirling
b26aa3417e Update build.gradle 2024-11-16 11:01:44 +00:00
Renan
8dfb5940ca Fixing bug: Add Image makes random changes to image (#2246) (#2256)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-11-16 08:55:40 +00:00
Anthony Stirling
0ce479e1e3 Update push-docker.yml 2024-11-16 08:43:42 +00:00
Anthony Stirling
cca3b6b525 Update multi-tool.html 2024-11-16 08:40:34 +00:00
github-actions[bot]
03529567ba 📝 Update README: Translation Progress Table (#2254)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-11-15 22:18:01 +00:00
Anthony Stirling
781a52c759 Update ignore_translation.toml 2024-11-15 22:15:36 +00:00
Anthony Stirling
be2c103065 Update build.gradle 2024-11-15 21:56:57 +00:00
albanobattistella
80fd2eff5f Update messages_it_IT.properties (#2250)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-11-15 21:53:39 +00:00
github-actions[bot]
65abfd9c7a Update translation files (#2252)
Signed-off-by: GitHub Action <action@github.com>
Co-authored-by: GitHub Action <action@github.com>
2024-11-15 21:52:28 +00:00
60 changed files with 594 additions and 196 deletions

179
.github/workflows/PR-Demo-Comment.yml vendored Normal file
View File

@@ -0,0 +1,179 @@
name: PR Deployment via Comment
on:
issue_comment:
types: [created]
jobs:
check-comment:
runs-on: ubuntu-latest
if: |
github.event.issue.pull_request &&
(
contains(github.event.comment.body, 'prdeploy') ||
contains(github.event.comment.body, 'deploypr')
)
&&
(
github.event.comment.user.login == 'frooodle' ||
github.event.comment.user.login == 'sf298' ||
github.event.comment.user.login == 'Ludy87' ||
github.event.comment.user.login == 'LaserKaspar' ||
github.event.comment.user.login == 'sbplat' ||
github.event.comment.user.login == 'reecebrowne'
)
outputs:
pr_number: ${{ steps.get-pr.outputs.pr_number }}
pr_repository: ${{ steps.get-pr-info.outputs.repository }}
pr_ref: ${{ steps.get-pr-info.outputs.ref }}
steps:
- name: Get PR data
id: get-pr
uses: actions/github-script@v7
with:
script: |
const prNumber = context.payload.issue.number;
console.log(`PR Number: ${prNumber}`);
core.setOutput('pr_number', prNumber);
- name: Get PR repository and ref
id: get-pr-info
uses: actions/github-script@v7
with:
script: |
const { owner, repo } = context.repo;
const prNumber = context.payload.issue.number;
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: prNumber,
});
// For forks, use the full repository name, for internal PRs use the current repo
const repository = pr.head.repo.fork ? pr.head.repo.full_name : `${owner}/${repo}`;
console.log(`PR Repository: ${repository}`);
console.log(`PR Branch: ${pr.head.ref}`);
core.setOutput('repository', repository);
core.setOutput('ref', pr.head.ref);
deploy-pr:
needs: check-comment
runs-on: ubuntu-latest
steps:
- name: Checkout PR
uses: actions/checkout@v4
with:
repository: ${{ needs.check-comment.outputs.pr_repository }}
ref: ${{ needs.check-comment.outputs.pr_ref }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Run Gradle Command
run: ./gradlew clean build
env:
DOCKER_ENABLE_SECURITY: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Get version number
id: versionNumber
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
- name: Build and push PR-specific image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }}
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64
- name: Set up SSH
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
sudo chmod 600 ../private.key
- name: Deploy to VPS
run: |
# First create the docker-compose content locally
cat > docker-compose.yml << 'EOF'
version: '3.3'
services:
stirling-pdf:
container_name: stirling-pdf-pr-${{ needs.check-comment.outputs.pr_number }}
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }}
ports:
- "${{ needs.check-comment.outputs.pr_number }}:8080"
volumes:
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/data:/usr/share/tessdata:rw
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/config:/configs:rw
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "false"
SECURITY_ENABLELOGIN: "false"
SYSTEM_DEFAULTLOCALE: en-GB
UI_APPNAME: "Stirling-PDF PR#${{ needs.check-comment.outputs.pr_number }}"
UI_HOMEDESCRIPTION: "PR#${{ needs.check-comment.outputs.pr_number }} for Stirling-PDF Latest"
UI_APPNAMENAVBAR: "PR#${{ needs.check-comment.outputs.pr_number }}"
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "false"
restart: on-failure:5
EOF
# Then copy the file and execute commands
scp -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null docker-compose.yml ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/docker-compose.yml
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
# Create PR-specific directories
mkdir -p /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/{data,config,logs}
# Move docker-compose file to correct location
mv /tmp/docker-compose.yml /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/docker-compose.yml
# Start or restart the container
cd /stirling/PR-${{ needs.check-comment.outputs.pr_number }}
docker-compose pull
docker-compose up -d
ENDSSH
- name: Post deployment URL to PR
if: success()
uses: actions/github-script@v7
with:
script: |
const { GITHUB_REPOSITORY } = process.env;
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
const prNumber = ${{ needs.check-comment.outputs.pr_number }};
const deploymentUrl = `http://${{ secrets.VPS_HOST }}:${prNumber}`;
const commentBody = `## 🚀 PR Test Deployment\n\n` +
`Your PR has been deployed for testing!\n\n` +
`🔗 **Test URL:** [${deploymentUrl}](${deploymentUrl})\n\n` +
`This deployment will be automatically cleaned up when the PR is closed.\n\n`;
await github.rest.issues.createComment({
owner: repoOwner,
repo: repoName,
issue_number: prNumber,
body: commentBody
});

78
.github/workflows/PR-Demo-cleanup.yml vendored Normal file
View File

@@ -0,0 +1,78 @@
name: PR Deployment cleanup
on:
pull_request:
types: [opened, synchronize, reopened, closed]
permissions:
contents: write
pull-requests: write
env:
SERVER_IP: ${{ secrets.VPS_IP }} # Add this to your GitHub secrets
CLEANUP_PERFORMED: 'false' # Add flag to track if cleanup occurred
jobs:
cleanup:
runs-on: ubuntu-latest
if: github.event.action == 'closed'
steps:
- name: Set up SSH
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
sudo chmod 600 ../private.key
- name: Cleanup PR deployment
id: cleanup
run: |
CLEANUP_STATUS=$(ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
if [ -d "/stirling/PR-${{ github.event.pull_request.number }}" ]; then
echo "Found PR directory, proceeding with cleanup..."
# Stop and remove containers
cd /stirling/PR-${{ github.event.pull_request.number }}
docker-compose down || true
# Go back to root before removal
cd /
# Remove PR-specific directories
rm -rf /stirling/PR-${{ github.event.pull_request.number }}
# Remove the Docker image
docker rmi --no-prune ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ github.event.pull_request.number }} || true
echo "PERFORMED_CLEANUP"
else
echo "PR directory not found, nothing to clean up"
echo "NO_CLEANUP_NEEDED"
fi
ENDSSH
)
if [[ $CLEANUP_STATUS == *"PERFORMED_CLEANUP"* ]]; then
echo "cleanup_performed=true" >> $GITHUB_OUTPUT
else
echo "cleanup_performed=false" >> $GITHUB_OUTPUT
fi
- name: Post cleanup notice to PR
if: steps.cleanup.outputs.cleanup_performed == 'true'
uses: actions/github-script@v7
with:
script: |
const { GITHUB_REPOSITORY } = process.env;
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
const prNumber = context.issue.number;
const commentBody = `## 🧹 Deployment Cleanup\n\n` +
`The test deployment for this PR has been cleaned up.`;
await github.rest.issues.createComment({
owner: repoOwner,
repo: repoName,
issue_number: prNumber,
body: commentBody
});

View File

@@ -9,6 +9,7 @@ on:
paths: paths:
- "src/main/resources/messages_en_GB.properties" - "src/main/resources/messages_en_GB.properties"
# Permissions required for the workflow
permissions: permissions:
contents: write contents: write
pull-requests: write pull-requests: write
@@ -18,6 +19,13 @@ jobs:
if: github.event_name == 'pull_request_target' if: github.event_name == 'pull_request_target'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout main branch first
uses: actions/checkout@v4
with:
ref: main
path: main-branch
fetch-depth: 0
- name: Checkout PR branch - name: Checkout PR branch
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
@@ -26,13 +34,6 @@ jobs:
path: pr-branch path: pr-branch
fetch-depth: 0 fetch-depth: 0
- name: Checkout main branch
uses: actions/checkout@v4
with:
ref: main
path: main-branch
fetch-depth: 0
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
@@ -49,34 +50,46 @@ jobs:
echo "Fetching PR changed files..." echo "Fetching PR changed files..."
cd pr-branch cd pr-branch
gh repo set-default ${{ github.repository }} gh repo set-default ${{ github.repository }}
gh pr view ${{ github.event.pull_request.number }} --json files -q ".files[].path" > ../changed_files.txt # Store files in a safe way, only allowing valid properties files
echo "Getting list of changed files from PR..."
gh pr view ${{ github.event.pull_request.number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]+\.properties$' > ../changed_files.txt
cd .. cd ..
echo $(cat changed_files.txt) echo "Setting branch path..."
BRANCH_PATH="pr-branch" BRANCH_PATH="pr-branch"
echo "BRANCH_PATH=${BRANCH_PATH}" >> $GITHUB_ENV echo "BRANCH_PATH=${BRANCH_PATH}" >> $GITHUB_ENV
CHANGED_FILES=$(cat changed_files.txt | tr '\n' ' ') echo "Processing changed files..."
echo "CHANGED_FILES=${CHANGED_FILES}" >> $GITHUB_ENV mapfile -t CHANGED_FILES < changed_files.txt
echo "Changed files: ${CHANGED_FILES}"
CHANGED_FILES_STR="${CHANGED_FILES[*]}"
echo "CHANGED_FILES=${CHANGED_FILES_STR}" >> $GITHUB_ENV
echo "Changed files: ${CHANGED_FILES_STR}"
echo "Branch: ${BRANCH_PATH}" echo "Branch: ${BRANCH_PATH}"
- name: Determine reference file - name: Determine reference file
id: determine-file id: determine-file
run: | run: |
echo "Determining reference file..." echo "Determining reference file..."
if echo "${{ env.CHANGED_FILES }}" | grep -q 'src/main/resources/messages_en_GB.properties'; then if grep -Fxq "src/main/resources/messages_en_GB.properties" changed_files.txt; then
echo "Using PR branch reference file"
echo "REFERENCE_FILE=pr-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV echo "REFERENCE_FILE=pr-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
else else
echo "Using main branch reference file"
echo "REFERENCE_FILE=main-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV echo "REFERENCE_FILE=main-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
fi fi
echo "REFERENCE_FILE=${{ env.REFERENCE_FILE }}"
- name: Show REFERENCE_FILE - name: Show REFERENCE_FILE
run: echo "Reference file is set to ${{ env.REFERENCE_FILE }}" run: echo "Reference file is set to ${REFERENCE_FILE}"
- name: Run Python script to check files - name: Run Python script to check files
id: run-check id: run-check
run: | run: |
python main-branch/.github/scripts/check_language_properties.py --reference-file ${{ env.REFERENCE_FILE }} --branch ${{ env.BRANCH_PATH }} --files ${{ env.CHANGED_FILES }} > failure.txt || true echo "Running Python script to check files..."
python main-branch/.github/scripts/check_language_properties.py \
--reference-file "${REFERENCE_FILE}" \
--branch "${BRANCH_PATH}" \
--files ${CHANGED_FILES} > failure.txt || true
- name: Capture output - name: Capture output
id: capture-output id: capture-output
@@ -87,7 +100,7 @@ jobs:
echo "ERROR_OUTPUT<<EOF" >> $GITHUB_ENV echo "ERROR_OUTPUT<<EOF" >> $GITHUB_ENV
echo "$ERROR_OUTPUT" >> $GITHUB_ENV echo "$ERROR_OUTPUT" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV
echo $ERROR_OUTPUT echo "${ERROR_OUTPUT}"
else else
echo "No errors found." echo "No errors found."
echo "ERROR_OUTPUT=" >> $GITHUB_ENV echo "ERROR_OUTPUT=" >> $GITHUB_ENV
@@ -110,7 +123,7 @@ jobs:
}); });
const comment = comments.data.find(c => c.body.includes("## 🚀 Translation Verification Summary")); const comment = comments.data.find(c => c.body.includes("## 🚀 Translation Verification Summary"));
// Only allow the action user to update comments // Only allow the action user to update comments
const expectedActor = "github-actions[bot]"; const expectedActor = "github-actions[bot]";
@@ -169,7 +182,10 @@ jobs:
- name: Run Python script to check files - name: Run Python script to check files
id: run-check id: run-check
run: | run: |
python .github/scripts/check_language_properties.py --reference-file src/main/resources/messages_en_GB.properties --branch main echo "Running Python script to check files..."
python .github/scripts/check_language_properties.py \
--reference-file src/main/resources/messages_en_GB.properties \
--branch main
- name: Set up git config - name: Set up git config
run: | run: |

View File

@@ -67,6 +67,7 @@ jobs:
images: | images: |
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf ${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf ${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
tags: | tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }} type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
@@ -95,6 +96,7 @@ jobs:
images: | images: |
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf ${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf ${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
tags: | tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }} type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
@@ -122,6 +124,7 @@ jobs:
images: | images: |
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf ${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf ${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
tags: | tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' }} type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' }}

View File

@@ -114,7 +114,7 @@ These files provide pre-configured setups for different scenarios. For example,
services: services:
stirling-pdf: stirling-pdf:
container_name: Stirling-PDF-Security container_name: Stirling-PDF-Security
image: frooodle/s-pdf:latest image: stirlingtools/stirling-pdf:latest
deploy: deploy:
resources: resources:
limits: limits:
@@ -173,20 +173,20 @@ Stirling-PDF uses different Docker images for various configurations. The build
For the latest version: For the latest version:
```bash ```bash
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile . docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest -f ./Dockerfile .
``` ```
For the ultra-lite version: For the ultra-lite version:
```bash ```bash
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite . docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
``` ```
For the fat version (with security enabled): For the fat version (with security enabled):
```bash ```bash
export DOCKER_ENABLE_SECURITY=true export DOCKER_ENABLE_SECURITY=true
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-fat -f ./Dockerfile-fat . docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile-fat .
``` ```
Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase

45
Jenkinsfile vendored
View File

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

View File

@@ -120,13 +120,13 @@ Please view the [LocalRunGuide](https://github.com/Stirling-Tools/Stirling-PDF/b
### Docker / Podman ### Docker / Podman
> [!NOTE] > [!NOTE]
> <https://hub.docker.com/r/frooodle/s-pdf> > <https://hub.docker.com/r/stirlingtools/stirling-pdf>
Stirling-PDF has three different versions: a full version, an ultra-lite version, and a 'fat' version. Depending on the types of features you use, you may want a smaller image to save on space. To see what the different versions offer, please look at our [version mapping](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Version-groups.md). For people that don't mind space optimization, just use the latest tag. Stirling-PDF has three different versions: a full version, an ultra-lite version, and a 'fat' version. Depending on the types of features you use, you may want a smaller image to save on space. To see what the different versions offer, please look at our [version mapping](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Version-groups.md). For people that don't mind space optimization, just use the latest tag.
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/frooodle/s-pdf/latest?label=Stirling-PDF%20Full) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/stirlingtools/stirling-pdf/latest?label=Stirling-PDF%20Full)
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/frooodle/s-pdf/latest-ultra-lite?label=Stirling-PDF%20Ultra-Lite) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/stirlingtools/stirling-pdf/latest-ultra-lite?label=Stirling-PDF%20Ultra-Lite)
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/frooodle/s-pdf/latest-fat?label=Stirling-PDF%20Fat) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/stirlingtools/stirling-pdf/latest-fat?label=Stirling-PDF%20Fat)
Please note in the examples below, you may need to change the volume paths as needed, e.g., `./extraConfigs:/configs` to `/opt/stirlingpdf/extraConfigs:/configs`. Please note in the examples below, you may need to change the volume paths as needed, e.g., `./extraConfigs:/configs` to `/opt/stirlingpdf/extraConfigs:/configs`.
@@ -144,7 +144,7 @@ docker run -d \
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \ -e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
-e LANGS=en_GB \ -e LANGS=en_GB \
--name stirling-pdf \ --name stirling-pdf \
frooodle/s-pdf:latest stirlingtools/stirling-pdf:latest
``` ```
### Docker Compose ### Docker Compose
@@ -153,7 +153,7 @@ docker run -d \
version: '3.3' version: '3.3'
services: services:
stirling-pdf: stirling-pdf:
image: frooodle/s-pdf:latest image: stirlingtools/stirling-pdf:latest
ports: ports:
- '8080:8080' - '8080:8080'
volumes: volumes:
@@ -190,29 +190,29 @@ Stirling-PDF currently supports 36 languages!
| Language | Progress | | Language | Progress |
| -------------------------------------------- | -------------------------------------- | | -------------------------------------------- | -------------------------------------- |
| Arabic (العربية) (ar_AR) | ![98%](https://geps.dev/progress/98) | | Arabic (العربية) (ar_AR) | ![97%](https://geps.dev/progress/97) |
| Basque (Euskara) (eu_ES) | ![55%](https://geps.dev/progress/55) | | Basque (Euskara) (eu_ES) | ![55%](https://geps.dev/progress/55) |
| Bulgarian (Български) (bg_BG) | ![97%](https://geps.dev/progress/97) | | Bulgarian (Български) (bg_BG) | ![96%](https://geps.dev/progress/96) |
| Catalan (Català) (ca_CA) | ![90%](https://geps.dev/progress/90) | | Catalan (Català) (ca_CA) | ![90%](https://geps.dev/progress/90) |
| Croatian (Hrvatski) (hr_HR) | ![98%](https://geps.dev/progress/98) | | Croatian (Hrvatski) (hr_HR) | ![98%](https://geps.dev/progress/98) |
| Czech (Česky) (cs_CZ) | ![98%](https://geps.dev/progress/98) | | Czech (Česky) (cs_CZ) | ![97%](https://geps.dev/progress/97) |
| Danish (Dansk) (da_DK) | ![97%](https://geps.dev/progress/97) | | Danish (Dansk) (da_DK) | ![96%](https://geps.dev/progress/96) |
| Dutch (Nederlands) (nl_NL) | ![96%](https://geps.dev/progress/96) | | Dutch (Nederlands) (nl_NL) | ![96%](https://geps.dev/progress/96) |
| 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) | ![97%](https://geps.dev/progress/97) | | French (Français) (fr_FR) | ![97%](https://geps.dev/progress/97) |
| German (Deutsch) (de_DE) | ![98%](https://geps.dev/progress/98) | | German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) |
| Greek (Ελληνικά) (el_GR) | ![98%](https://geps.dev/progress/98) | | Greek (Ελληνικά) (el_GR) | ![97%](https://geps.dev/progress/97) |
| Hindi (हिंदी) (hi_IN) | ![95%](https://geps.dev/progress/95) | | Hindi (हिंदी) (hi_IN) | ![95%](https://geps.dev/progress/95) |
| Hungarian (Magyar) (hu_HU) | ![98%](https://geps.dev/progress/98) | | Hungarian (Magyar) (hu_HU) | ![98%](https://geps.dev/progress/98) |
| Indonesian (Bahasa Indonesia) (id_ID) | ![98%](https://geps.dev/progress/98) | | Indonesian (Bahasa Indonesia) (id_ID) | ![97%](https://geps.dev/progress/97) |
| Irish (Gaeilge) (ga_IE) | ![88%](https://geps.dev/progress/88) | | Irish (Gaeilge) (ga_IE) | ![88%](https://geps.dev/progress/88) |
| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) | | Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
| Japanese (日本語) (ja_JP) | ![86%](https://geps.dev/progress/86) | | Japanese (日本語) (ja_JP) | ![85%](https://geps.dev/progress/85) |
| Korean (한국어) (ko_KR) | ![96%](https://geps.dev/progress/96) | | Korean (한국어) (ko_KR) | ![95%](https://geps.dev/progress/95) |
| Norwegian (Norsk) (no_NB) | ![88%](https://geps.dev/progress/88) | | Norwegian (Norsk) (no_NB) | ![87%](https://geps.dev/progress/87) |
| Polish (Polski) (pl_PL) | ![97%](https://geps.dev/progress/97) | | Polish (Polski) (pl_PL) | ![97%](https://geps.dev/progress/97) |
| Portuguese (Português) (pt_PT) | ![98%](https://geps.dev/progress/98) | | Portuguese (Português) (pt_PT) | ![97%](https://geps.dev/progress/97) |
| Portuguese Brazilian (Português) (pt_BR) | ![98%](https://geps.dev/progress/98) | | Portuguese Brazilian (Português) (pt_BR) | ![98%](https://geps.dev/progress/98) |
| Romanian (Română) (ro_RO) | ![90%](https://geps.dev/progress/90) | | Romanian (Română) (ro_RO) | ![90%](https://geps.dev/progress/90) |
| Russian (Русский) (ru_RU) | ![97%](https://geps.dev/progress/97) | | Russian (Русский) (ru_RU) | ![97%](https://geps.dev/progress/97) |
@@ -225,7 +225,7 @@ Stirling-PDF currently supports 36 languages!
| Traditional Chinese (繁體中文) (zh_TW) | ![98%](https://geps.dev/progress/98) | | Traditional Chinese (繁體中文) (zh_TW) | ![98%](https://geps.dev/progress/98) |
| Turkish (Türkçe) (tr_TR) | ![92%](https://geps.dev/progress/92) | | Turkish (Türkçe) (tr_TR) | ![92%](https://geps.dev/progress/92) |
| Ukrainian (Українська) (uk_UA) | ![80%](https://geps.dev/progress/80) | | Ukrainian (Українська) (uk_UA) | ![80%](https://geps.dev/progress/80) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![89%](https://geps.dev/progress/89) | | Vietnamese (Tiếng Việt) (vi_VN) | ![88%](https://geps.dev/progress/88) |
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.) ## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)

View File

@@ -10,6 +10,8 @@ plugins {
//id "nebula.lint" version "19.0.3" //id "nebula.lint" version "19.0.3"
} }
import com.github.jk1.license.render.* import com.github.jk1.license.render.*
ext { ext {
@@ -17,12 +19,12 @@ ext {
pdfboxVersion = "3.0.3" pdfboxVersion = "3.0.3"
logbackVersion = "1.5.7" logbackVersion = "1.5.7"
imageioVersion = "3.12.0" imageioVersion = "3.12.0"
lombokVersion = "1.18.34" lombokVersion = "1.18.36"
bouncycastleVersion = "1.78.1" bouncycastleVersion = "1.78.1"
} }
group = "stirling.software" group = "stirling.software"
version = "0.32.0" version = "0.33.1"
java { java {
// 17 is lowest but we support and recommend 21 // 17 is lowest but we support and recommend 21

View File

@@ -1,7 +1,7 @@
services: services:
stirling-pdf: stirling-pdf:
container_name: Stirling-PDF-Security-Fat container_name: Stirling-PDF-Security-Fat
image: frooodle/s-pdf:latest-fat image: stirlingtools/stirling-pdf:latest-fat
deploy: deploy:
resources: resources:
limits: limits:

View File

@@ -1,7 +1,7 @@
services: services:
stirling-pdf: stirling-pdf:
container_name: Stirling-PDF-Security container_name: Stirling-PDF-Security
image: frooodle/s-pdf:latest image: stirlingtools/stirling-pdf:latest
deploy: deploy:
resources: resources:
limits: limits:

View File

@@ -1,7 +1,7 @@
services: services:
stirling-pdf: stirling-pdf:
container_name: Stirling-PDF-Security container_name: Stirling-PDF-Security
image: frooodle/s-pdf:latest image: stirlingtools/stirling-pdf:latest
deploy: deploy:
resources: resources:
limits: limits:

View File

@@ -1,7 +1,7 @@
services: services:
stirling-pdf: stirling-pdf:
container_name: Stirling-PDF-Ultra-Lite-Security container_name: Stirling-PDF-Ultra-Lite-Security
image: frooodle/s-pdf:latest-ultra-lite image: stirlingtools/stirling-pdf:latest-ultra-lite
deploy: deploy:
resources: resources:
limits: limits:

View File

@@ -1,7 +1,7 @@
services: services:
stirling-pdf: stirling-pdf:
container_name: Stirling-PDF-Ultra-Lite container_name: Stirling-PDF-Ultra-Lite
image: frooodle/s-pdf:latest-ultra-lite image: stirlingtools/stirling-pdf:latest-ultra-lite
deploy: deploy:
resources: resources:
limits: limits:

View File

@@ -1,7 +1,7 @@
services: services:
stirling-pdf: stirling-pdf:
container_name: Stirling-PDF container_name: Stirling-PDF
image: frooodle/s-pdf:latest image: stirlingtools/stirling-pdf:latest
deploy: deploy:
resources: resources:
limits: limits:

View File

@@ -32,12 +32,12 @@ ignore = [
ignore = [ ignore = [
'AddStampRequest.alphabet', 'AddStampRequest.alphabet',
'AddStampRequest.position', 'AddStampRequest.position',
'home.pipeline.title'
'PDFToBook.selectText.1', 'PDFToBook.selectText.1',
'PDFToText.tags', 'PDFToText.tags',
'addPageNumbers.selectText.3', 'addPageNumbers.selectText.3',
'alphabet', 'alphabet',
'certSign.name', 'certSign.name',
'home.pipeline.title',
'language.direction', 'language.direction',
'licenses.version', 'licenses.version',
'pipeline.title', 'pipeline.title',
@@ -46,7 +46,6 @@ ignore = [
'sponsor', 'sponsor',
'text', 'text',
'watermark.type.1', 'watermark.type.1',
'certSign.name',
] ]
[el_GR] [el_GR]

View File

@@ -34,6 +34,12 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
@Value("${spring.datasource.url}") @Value("${spring.datasource.url}")
private String url; private String url;
@Value("${spring.datasource.username}")
private String databaseUsername;
@Value("${spring.datasource.password}")
private String databasePassword;
private Path backupPath = Paths.get("configs/db/backup/"); private Path backupPath = Paths.get("configs/db/backup/");
@Override @Override
@@ -134,7 +140,8 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql"); this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql");
String query = "SCRIPT SIMPLE COLUMNS DROP to ?;"; String query = "SCRIPT SIMPLE COLUMNS DROP to ?;";
try (Connection conn = DriverManager.getConnection(url, "sa", ""); try (Connection conn =
DriverManager.getConnection(url, databaseUsername, databasePassword);
PreparedStatement stmt = conn.prepareStatement(query)) { PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, insertOutputFilePath.toString()); stmt.setString(1, insertOutputFilePath.toString());
stmt.execute(); stmt.execute();
@@ -147,7 +154,8 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
// Retrieves the H2 database version. // Retrieves the H2 database version.
public String getH2Version() { public String getH2Version() {
String version = "Unknown"; String version = "Unknown";
try (Connection conn = DriverManager.getConnection(url, "sa", "")) { try (Connection conn =
DriverManager.getConnection(url, databaseUsername, databasePassword)) {
try (Statement stmt = conn.createStatement(); try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) { ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
if (rs.next()) { if (rs.next()) {
@@ -189,7 +197,8 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
private boolean executeDatabaseScript(Path scriptPath) { private boolean executeDatabaseScript(Path scriptPath) {
String query = "RUNSCRIPT from ?;"; String query = "RUNSCRIPT from ?;";
try (Connection conn = DriverManager.getConnection(url, "sa", ""); try (Connection conn =
DriverManager.getConnection(url, databaseUsername, databasePassword);
PreparedStatement stmt = conn.prepareStatement(query)) { PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, scriptPath.toString()); stmt.setString(1, scriptPath.toString());
stmt.execute(); stmt.execute();

View File

@@ -32,11 +32,19 @@ public class MetricsAggregatorService {
.counters() .counters()
.forEach( .forEach(
counter -> { counter -> {
String key = String method = counter.getId().getTag("method");
String.format( String uri = counter.getId().getTag("uri");
"http_requests_%s_%s",
counter.getId().getTag("method"), // Skip if either method or uri is null
counter.getId().getTag("uri").replace("/", "_")); if (method == null || uri == null) {
return;
}
String key = String.format(
"http_requests_%s_%s",
method,
uri.replace("/", "_")
);
double currentCount = counter.count(); double currentCount = counter.count();
double lastCount = lastSentMetrics.getOrDefault(key, 0.0); double lastCount = lastSentMetrics.getOrDefault(key, 0.0);

View File

@@ -81,6 +81,7 @@ page=صفحة
pages=صفحات pages=صفحات
loading=جارٍ التحميل... loading=جارٍ التحميل...
addToDoc=إضافة إلى المستند addToDoc=إضافة إلى المستند
reset=Reset
legal.privacy=سياسة الخصوصية legal.privacy=سياسة الخصوصية
legal.terms=شروط الاستخدام legal.terms=شروط الاستخدام

View File

@@ -81,6 +81,7 @@ page=Страница
pages=Страници pages=Страници
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Политика за поверителност legal.privacy=Политика за поверителност
legal.terms=Правила и условия legal.terms=Правила и условия

View File

@@ -81,6 +81,7 @@ page=Pàgina
pages=Pàgines pages=Pàgines
loading=Carregant... loading=Carregant...
addToDoc=Afegeix al document addToDoc=Afegeix al document
reset=Reset
legal.privacy=Política de Privacitat legal.privacy=Política de Privacitat
legal.terms=Termes i condicions legal.terms=Termes i condicions

View File

@@ -81,6 +81,7 @@ page=Strana
pages=Strany pages=Strany
loading=Načítání... loading=Načítání...
addToDoc=Přidat do dokumentu addToDoc=Přidat do dokumentu
reset=Reset
legal.privacy=Politika soukromí legal.privacy=Politika soukromí
legal.terms=Podmínky použití legal.terms=Podmínky použití

View File

@@ -81,6 +81,7 @@ page=Sidenummer
pages=Sideantal pages=Sideantal
loading=Laster... loading=Laster...
addToDoc=Tilføj til Dokument addToDoc=Tilføj til Dokument
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Vilkår og betingelser legal.terms=Vilkår og betingelser

View File

@@ -81,6 +81,7 @@ page=Seite
pages=Seiten pages=Seiten
loading=Laden... loading=Laden...
addToDoc=In Dokument hinzufügen addToDoc=In Dokument hinzufügen
reset=Reset
legal.privacy=Datenschutz legal.privacy=Datenschutz
legal.terms=AGB legal.terms=AGB

View File

@@ -81,6 +81,7 @@ page=Σελίδα
pages=Σελίδες pages=Σελίδες
loading=Φόρτωση... loading=Φόρτωση...
addToDoc=Πρόσθεση στο Εκπομπώματο addToDoc=Πρόσθεση στο Εκπομπώματο
reset=Reset
legal.privacy=Πολιτική Προνομίους legal.privacy=Πολιτική Προνομίους
legal.terms=Φράσεις Υποχρεωτικότητας legal.terms=Φράσεις Υποχρεωτικότητας

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=Página
pages=Páginas pages=Páginas
loading=Cargando... loading=Cargando...
addToDoc=Agregar al Documento addToDoc=Agregar al Documento
reset=Reset
legal.privacy=Política de Privacidad legal.privacy=Política de Privacidad
legal.terms=Términos y Condiciones legal.terms=Términos y Condiciones

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Chargement... loading=Chargement...
addToDoc=Ajouter au Document addToDoc=Ajouter au Document
reset=Reset
legal.privacy=Politique de Confidentialité legal.privacy=Politique de Confidentialité
legal.terms=Conditions Générales legal.terms=Conditions Générales

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=पृष्ठ
pages=पृष्ठों pages=पृष्ठों
loading=डालिंग... loading=डालिंग...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=गुप्तता सूचना legal.privacy=गुप्तता सूचना
legal.terms=शर्तें और प्रवाह legal.terms=शर्तें और प्रवाह

View File

@@ -81,6 +81,7 @@ page=Stranica
pages=Stranice pages=Stranice
loading=Učitavanje... loading=Učitavanje...
addToDoc=Dodaj u dokument addToDoc=Dodaj u dokument
reset=Reset
legal.privacy=Politika privatnosti legal.privacy=Politika privatnosti
legal.terms=Uspe sodržine legal.terms=Uspe sodržine

View File

@@ -81,6 +81,7 @@ page=Oldal
pages=Oldalak pages=Oldalak
loading=Betöltés... loading=Betöltés...
addToDoc=Hozzáadás dokumentumba addToDoc=Hozzáadás dokumentumba
reset=Reset
legal.privacy=Adatvédelmi nyilatkozat legal.privacy=Adatvédelmi nyilatkozat
legal.terms=Feltételek és feltételek legal.terms=Feltételek és feltételek

View File

@@ -81,6 +81,7 @@ page=Halaman
pages=Halaman-halaman pages=Halaman-halaman
loading=Mengambil data... loading=Mengambil data...
addToDoc=Tambahkan ke Dokumen addToDoc=Tambahkan ke Dokumen
reset=Reset
legal.privacy=Kebijakan Privasi legal.privacy=Kebijakan Privasi
legal.terms=Syarat dan Ketentuan legal.terms=Syarat dan Ketentuan

View File

@@ -81,6 +81,7 @@ page=Pagina
pages=Pagine pages=Pagine
loading=Caricamento... loading=Caricamento...
addToDoc=Aggiungi al documento addToDoc=Aggiungi al documento
reset=Reset
legal.privacy=Informativa sulla privacy legal.privacy=Informativa sulla privacy
legal.terms=Termini e Condizioni legal.terms=Termini e Condizioni
@@ -141,7 +142,7 @@ navbar.language=Lingue
navbar.settings=Impostazioni navbar.settings=Impostazioni
navbar.allTools=Strumenti navbar.allTools=Strumenti
navbar.multiTool=Strumenti multipli navbar.multiTool=Strumenti multipli
navbar.search=Search navbar.search=Cerca
navbar.sections.organize=Organizza navbar.sections.organize=Organizza
navbar.sections.convertTo=Converti in PDF navbar.sections.convertTo=Converti in PDF
navbar.sections.convertFrom=Converti da PDF navbar.sections.convertFrom=Converti da PDF
@@ -944,7 +945,7 @@ multiTool.downloadAll=Esporta
multiTool.downloadSelected=Esporta selezionata multiTool.downloadSelected=Esporta selezionata
#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=Questa funzione è disponibile anche nella nostra <a href="{0}">pagina multi-strumento</a>. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive!
#view pdf #view pdf
viewPdf.title=Visualizza PDF viewPdf.title=Visualizza PDF

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=プライバシーポリシー legal.privacy=プライバシーポリシー
legal.terms=利用規約 legal.terms=利用規約

View File

@@ -81,6 +81,7 @@ page=페이지
pages=페이지 pages=페이지
loading=로딩 중... loading=로딩 중...
addToDoc=문서에 추가 addToDoc=문서에 추가
reset=Reset
legal.privacy=개인 정보 정책 legal.privacy=개인 정보 정책
legal.terms=이용 약관 legal.terms=이용 약관

View File

@@ -81,6 +81,7 @@ page=Pagina
pages=Pagen pages=Pagen
loading=Laden... loading=Laden...
addToDoc=Toevoegen aan document addToDoc=Toevoegen aan document
reset=Reset
legal.privacy=Privacybeleid legal.privacy=Privacybeleid
legal.terms=Voorwaarden van gebruik legal.terms=Voorwaarden van gebruik

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=Strona
pages=Strony pages=Strony
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Polityka Prywatności legal.privacy=Polityka Prywatności
legal.terms=Zasady i Postanowienia legal.terms=Zasady i Postanowienia

View File

@@ -81,6 +81,7 @@ page=Página
pages=Páginas pages=Páginas
loading=Carregando... loading=Carregando...
addToDoc=Adicionar ao Documento addToDoc=Adicionar ao Documento
reset=Reset
legal.privacy=Política de Privacidade legal.privacy=Política de Privacidade
legal.terms=Termos e Condições legal.terms=Termos e Condições

View File

@@ -81,6 +81,7 @@ page=Página
pages=Páginas pages=Páginas
loading=A carregar... loading=A carregar...
addToDoc=Adicionar ao Documento addToDoc=Adicionar ao Documento
reset=Reset
legal.privacy=Política de Privacidade legal.privacy=Política de Privacidade
legal.terms=Termos e Condições legal.terms=Termos e Condições

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=Страница
pages=Страницы pages=Страницы
loading=Загрузка... loading=Загрузка...
addToDoc=Добавить в документ addToDoc=Добавить в документ
reset=Reset
legal.privacy=Политика конфиденциальности legal.privacy=Политика конфиденциальности
legal.terms=Условия использования legal.terms=Условия использования

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=Sidan
pages=Sidor pages=Sidor
loading=Laddar... loading=Laddar...
addToDoc=Lägg till i dokument addToDoc=Lägg till i dokument
reset=Reset
legal.privacy=Dataprotektionspolicy legal.privacy=Dataprotektionspolicy
legal.terms=Villkor och betingelser legal.terms=Villkor och betingelser

View File

@@ -81,6 +81,7 @@ page=หน้า
pages=หน้า pages=หน้า
loading=กำลังโหลด... loading=กำลังโหลด...
addToDoc=เพิ่มเข้าสู่เอกสาร addToDoc=เพิ่มเข้าสู่เอกสาร
reset=Reset
legal.privacy=นโยบายความเป็นส่วนตัว legal.privacy=นโยบายความเป็นส่วนตัว
legal.terms=ข้อกำหนดการใช้งาน legal.terms=ข้อกำหนดการใช้งาน

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Gizlilik Politikası legal.privacy=Gizlilik Politikası
legal.terms=Şartlar ve koşullar legal.terms=Şartlar ve koşullar

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=Page
pages=Pages pages=Pages
loading=Loading... loading=Loading...
addToDoc=Add to Document addToDoc=Add to Document
reset=Reset
legal.privacy=Privacy Policy legal.privacy=Privacy Policy
legal.terms=Terms and Conditions legal.terms=Terms and Conditions

View File

@@ -81,6 +81,7 @@ page=頁面
pages=頁面 pages=頁面
loading=載入中... loading=載入中...
addToDoc=新增至文件 addToDoc=新增至文件
reset=Reset
legal.privacy=隱私權政策 legal.privacy=隱私權政策
legal.terms=使用條款 legal.terms=使用條款

View File

@@ -140,7 +140,7 @@ span.icon-text::after {
position: relative; position: relative;
} }
.tooltip-text { /* .tooltip-text {
visibility: hidden; visibility: hidden;
background-color: rgb(71 67 67 / 80%); background-color: rgb(71 67 67 / 80%);
color: #fff; color: #fff;
@@ -162,7 +162,7 @@ span.icon-text::after {
.nav-item:hover .tooltip-text { .nav-item:hover .tooltip-text {
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
} } */
.dropdown-menu.scrollable-y { .dropdown-menu.scrollable-y {
overflow-y: scroll; overflow-y: scroll;
@@ -324,6 +324,18 @@ span.icon-text::after {
margin-top: 0; margin-top: 0;
} }
/* .icon-hide {
display: none;
} */
}
@media (max-width:1199px) {
.icon-hide {
display: inline-flex;
}
}
@media (min-width:1200px) {
.icon-hide { .icon-hide {
display: none; display: none;
} }

View File

@@ -96,14 +96,31 @@
}); });
}); });
async function getPDFPageCount(file) {
try {
const arrayBuffer = await file.arrayBuffer();
pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs-legacy/pdf.worker.mjs'
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
return pdf.numPages;
} catch (error) {
console.error('Error getting PDF page count:', error);
return null;
}
}
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) { async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
const startTime = performance.now();
const file = formData.get('fileInput');
let success = false;
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;
if (response.status === 401) { if (response.status === 401) {
// Handle 401 Unauthorized error
showSessionExpiredPrompt(); showSessionExpiredPrompt();
return; return;
} }
@@ -118,6 +135,8 @@
let filename = getFilenameFromContentDisposition(contentDisposition); let filename = getFilenameFromContentDisposition(contentDisposition);
const blob = await response.blob(); const blob = await response.blob();
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);
@@ -127,13 +146,29 @@
} }
} catch (error) { } catch (error) {
success = false;
errorMessage = error.message;
clearFileInput(); clearFileInput();
console.error("Error in handleSingleDownload:", error); console.error("Error in handleSingleDownload:", error);
throw error; throw error;
} finally {
const processingTime = performance.now() - startTime;
// Capture analytics
const pageCount = file && file.type === 'application/pdf' ? await getPDFPageCount(file) : null;
posthog.capture('file_processing', {
success: success,
file_type: file ? file.type || 'unknown' : 'unknown',
file_size: file ? file.size : 0,
processing_time: processingTime,
error_message: errorMessage,
pdf_pages: pageCount
});
} }
} }
function getFilenameFromContentDisposition(contentDisposition) { function getFilenameFromContentDisposition(contentDisposition) {
let filename; let filename;
if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) { if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) {
@@ -145,7 +180,7 @@
return filename; return filename;
} }
async function handleJsonResponse(response) { async function handleJsonResponse(response) {
const json = await response.json(); const json = await response.json();
const errorMessage = JSON.stringify(json, null, 2); const errorMessage = JSON.stringify(json, null, 2);
@@ -308,14 +343,14 @@
if(editSectionElement){ if(editSectionElement){
editSectionElement.style.display = "none"; editSectionElement.style.display = "none";
} }
let cropPdfCanvas = document.querySelector("#crop-pdf-canvas"); 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.heigth = 0; cropPdfCanvas.height = 0;
overlayCanvas.width = 0; overlayCanvas.width = 0;
overlayCanvas.heigth = 0; overlayCanvas.height = 0;
} }
} else{ } else{
console.log("Disabled for 'Merge'"); console.log("Disabled for 'Merge'");

View File

@@ -9,81 +9,81 @@ const DraggableUtils = {
init() { init() {
interact(".draggable-canvas") interact(".draggable-canvas")
.draggable({ .draggable({
listeners: { listeners: {
move: (event) => { move: (event) => {
const target = event.target; const target = event.target;
const x = (parseFloat(target.getAttribute("data-bs-x")) || 0) const x = (parseFloat(target.getAttribute("data-bs-x")) || 0)
+ event.dx; + event.dx;
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0) const y = (parseFloat(target.getAttribute("data-bs-y")) || 0)
+ event.dy; + event.dy;
target.style.transform = `translate(${x}px, ${y}px)`; target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute("data-bs-x", x); target.setAttribute("data-bs-x", x);
target.setAttribute("data-bs-y", y); target.setAttribute("data-bs-y", y);
this.onInteraction(target); this.onInteraction(target);
//update the last interacted element //update the last interacted element
this.lastInteracted = event.target; this.lastInteracted = event.target;
},
}, },
}, })
}) .resizable({
.resizable({ edges: { left: true, right: true, bottom: true, top: true },
edges: { left: true, right: true, bottom: true, top: true }, listeners: {
listeners: { move: (event) => {
move: (event) => { var target = event.target;
var target = event.target; var x = parseFloat(target.getAttribute("data-bs-x")) || 0;
var x = parseFloat(target.getAttribute("data-bs-x")) || 0; var y = parseFloat(target.getAttribute("data-bs-y")) || 0;
var y = parseFloat(target.getAttribute("data-bs-y")) || 0;
// check if control key is pressed // check if control key is pressed
if (event.ctrlKey) { if (event.ctrlKey) {
const aspectRatio = target.offsetWidth / target.offsetHeight; const aspectRatio = target.offsetWidth / target.offsetHeight;
// preserve aspect ratio // preserve aspect ratio
let width = event.rect.width; let width = event.rect.width;
let height = event.rect.height; let height = event.rect.height;
if (Math.abs(event.deltaRect.width) >= Math.abs( if (Math.abs(event.deltaRect.width) >= Math.abs(
event.deltaRect.height)) { event.deltaRect.height)) {
height = width / aspectRatio; height = width / aspectRatio;
} else { } else {
width = height * aspectRatio; width = height * aspectRatio;
}
event.rect.width = width;
event.rect.height = height;
} }
event.rect.width = width; target.style.width = event.rect.width + "px";
event.rect.height = height; target.style.height = event.rect.height + "px";
}
target.style.width = event.rect.width + "px"; // translate when resizing from top or left edges
target.style.height = event.rect.height + "px"; x += event.deltaRect.left;
y += event.deltaRect.top;
// translate when resizing from top or left edges target.style.transform = "translate(" + x + "px," + y + "px)";
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.transform = "translate(" + x + "px," + y + "px)"; target.setAttribute("data-bs-x", x);
target.setAttribute("data-bs-y", y);
target.setAttribute("data-bs-x", x); target.textContent = Math.round(event.rect.width) + "\u00D7"
target.setAttribute("data-bs-y", y);
target.textContent = Math.round(event.rect.width) + "\u00D7"
+ Math.round(event.rect.height); + Math.round(event.rect.height);
this.onInteraction(target); this.onInteraction(target);
},
}, },
},
modifiers: [ modifiers: [
interact.modifiers.restrictSize({ interact.modifiers.restrictSize({
min: {width: 5, height: 5}, min: { width: 5, height: 5 },
}), }),
], ],
inertia: true, inertia: true,
}); });
//Arrow key Support for Add-Image and Sign pages //Arrow key Support for Add-Image and Sign pages
if(window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) { if (window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) {
window.addEventListener('keydown', (event) => { window.addEventListener('keydown', (event) => {
//Check for last interacted element //Check for last interacted element
if (!this.lastInteracted){ if (!this.lastInteracted) {
return; return;
} }
// Get the currently selected element // Get the currently selected element
@@ -288,7 +288,7 @@ const DraggableUtils = {
} }
}, },
parseTransform(element) {}, parseTransform(element) { },
async getOverlayedPdfDocument() { async getOverlayedPdfDocument() {
const pdfBytes = await this.pdfDoc.getData(); const pdfBytes = await this.pdfDoc.getData();
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, {
@@ -308,6 +308,7 @@ const DraggableUtils = {
const offsetWidth = pagesMap[pageIdx + "-offsetWidth"]; const offsetWidth = pagesMap[pageIdx + "-offsetWidth"];
const offsetHeight = pagesMap[pageIdx + "-offsetHeight"]; const offsetHeight = pagesMap[pageIdx + "-offsetHeight"];
for (const draggableData of draggablesData) { for (const draggableData of draggablesData) {
// embed the draggable canvas // embed the draggable canvas
const draggableElement = draggableData.element; const draggableElement = draggableData.element;
@@ -324,6 +325,24 @@ const DraggableUtils = {
width: draggableData.offsetWidth, width: draggableData.offsetWidth,
height: draggableData.offsetHeight, height: draggableData.offsetHeight,
}; };
//Auxiliary variables
let widthAdjusted = page.getWidth();
let heightAdjusted = page.getHeight();
const rotation = page.getRotation();
//Normalizing angle
let normalizedAngle = rotation.angle % 360;
if (normalizedAngle < 0) {
normalizedAngle += 360;
}
//Changing the page dimension if the angle is 90 or 270
if (normalizedAngle === 90 || normalizedAngle === 270) {
let widthTemp = widthAdjusted;
widthAdjusted = heightAdjusted;
heightAdjusted = widthTemp;
}
const draggablePositionRelative = { const draggablePositionRelative = {
x: draggablePositionPixels.x / offsetWidth, x: draggablePositionPixels.x / offsetWidth,
y: draggablePositionPixels.y / offsetHeight, y: draggablePositionPixels.y / offsetHeight,
@@ -331,18 +350,36 @@ const DraggableUtils = {
height: draggablePositionPixels.height / offsetHeight, height: draggablePositionPixels.height / offsetHeight,
}; };
const draggablePositionPdf = { const draggablePositionPdf = {
x: draggablePositionRelative.x * page.getWidth(), x: draggablePositionRelative.x * widthAdjusted,
y: draggablePositionRelative.y * page.getHeight(), y: draggablePositionRelative.y * heightAdjusted,
width: draggablePositionRelative.width * page.getWidth(), width: draggablePositionRelative.width * widthAdjusted,
height: draggablePositionRelative.height * page.getHeight(), height: draggablePositionRelative.height * heightAdjusted,
}; };
//Defining the image if the page has a 0-degree angle
let x = draggablePositionPdf.x
let y = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height
//Defining the image position if it is at other angles
if (normalizedAngle === 90) {
x = draggablePositionPdf.y + draggablePositionPdf.height;
y = draggablePositionPdf.x;
} else if (normalizedAngle === 180) {
x = widthAdjusted - draggablePositionPdf.x;
y = draggablePositionPdf.y + draggablePositionPdf.height;
} else if (normalizedAngle === 270) {
x = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height;
y = widthAdjusted - draggablePositionPdf.x;
}
// draw the image // draw the image
page.drawImage(pdfImageObject, { page.drawImage(pdfImageObject, {
x: draggablePositionPdf.x, x: x,
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height, y: y,
width: draggablePositionPdf.width, width: draggablePositionPdf.width,
height: draggablePositionPdf.height, height: draggablePositionPdf.height,
rotate: rotation
}); });
} }
} }

View File

@@ -23,23 +23,26 @@
</form> </form>
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p> <p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>
<div style="position: relative; display: inline-block;"> <div style="position: relative; width: auto;" id="canvasesContainer">
<div> <div>
<div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container"> <div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container">
<button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> &lt; </button> <button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> &lt; </button>
<button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> &gt; </button> <button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> &gt; </button>
</div> </div>
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas> <canvas id="cropPdfCanvas" style="width: 100%"></canvas>
</div> </div>
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas> <canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2; width: 100%"></canvas>
</div> </div>
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script> <script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
<script> <script>
let pdfCanvas = document.getElementById('crop-pdf-canvas'); let pdfCanvas = document.getElementById('cropPdfCanvas');
let overlayCanvas = document.getElementById('overlayCanvas'); let overlayCanvas = document.getElementById('overlayCanvas');
let canvasesContainer = document.getElementById('canvasesContainer');
canvasesContainer.style.display = "none";
// let paginationBtnContainer = ; // let paginationBtnContainer = ;
let context = pdfCanvas.getContext('2d'); let context = pdfCanvas.getContext('2d');
let overlayContext = overlayCanvas.getContext('2d');
let btn1Object = document.getElementById('previous-page-btn'); let btn1Object = document.getElementById('previous-page-btn');
let btn2Object = document.getElementById('next-page-btn'); let btn2Object = document.getElementById('next-page-btn');
@@ -60,6 +63,8 @@
let rectWidth = 0; let rectWidth = 0;
let rectHeight = 0; let rectHeight = 0;
let timeId = null; // timeout id for resizing canvases event
btn1Object.addEventListener('click',function (e){ btn1Object.addEventListener('click',function (e){
if (currentPage !== 1) { if (currentPage !== 1) {
currentPage = currentPage - 1; currentPage = currentPage - 1;
@@ -102,14 +107,13 @@
} }
}); });
fileInput.addEventListener('change', function(e) { function renderPageFromFile(file) {
file = e.target.files[0];
if (file.type === 'application/pdf') { if (file.type === 'application/pdf') {
let reader = new FileReader(); let reader = new FileReader();
reader.onload = function(ev) { reader.onload = function (ev) {
let typedArray = new Uint8Array(reader.result); let typedArray = new Uint8Array(reader.result);
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
pdfjsLib.getDocument(typedArray).promise.then(function(pdf) { pdfjsLib.getDocument(typedArray).promise.then(function (pdf) {
pdfDoc = pdf; pdfDoc = pdf;
totalPages = pdf.numPages; totalPages = pdf.numPages;
renderPage(currentPage); renderPage(currentPage);
@@ -117,9 +121,37 @@
pageId.value = currentPage; pageId.value = currentPage;
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
document.getElementById("pagination-button-container").style.display="flex"; document.getElementById("pagination-button-container").style.display = "flex";
document.getElementById("instruction-text").style.display="block"; document.getElementById("instruction-text").style.display = "block";
} }
}
window.addEventListener("resize", function() {
clearTimeout(timeId);
timeId = setTimeout(function () {
if (fileInput.files.length == 0) return;
let canvasesContainer = document.getElementById('canvasesContainer');
let containerRect = canvasesContainer.getBoundingClientRect();
context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height);
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
pdfCanvas.width = containerRect.width;
pdfCanvas.height = containerRect.height;
overlayCanvas.width = containerRect.width;
overlayCanvas.height = containerRect.height;
let file = fileInput.files[0];
renderPageFromFile(file);
}, 1000);
});
fileInput.addEventListener('change', function(e) {
canvasesContainer.style.display = "block"; // set for visual purposes
file = e.target.files[0];
renderPageFromFile(file);
}); });
function renderPage(pageNumber) { function renderPage(pageNumber) {

View File

@@ -201,6 +201,7 @@
window.stirlingPDF.error = /*[[#{error}]]*/ "Error"; window.stirlingPDF.error = /*[[#{error}]]*/ "Error";
})(); })();
</script> </script>
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
<script th:src="@{'/js/downloader.js'}"></script> <script th:src="@{'/js/downloader.js'}"></script>
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}"> <div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
@@ -218,4 +219,4 @@
</div> </div>
</div> </div>
<script th:src="@{'/js/fileInput.js'}"></script> <script th:src="@{'/js/fileInput.js'}"></script>
</th:block> </th:block>

View File

@@ -330,7 +330,7 @@
<span class="material-symbols-rounded" id="dark-mode-icon"> <span class="material-symbols-rounded" id="dark-mode-icon">
dark_mode dark_mode
</span> </span>
<span class="icon-text icon-hide tooltip-text" id="dark-mode-text" th:data-text="#{navbar.darkmode}" th:text="#{navbar.darkmode}"></span> <span class="icon-text icon-hide" id="dark-mode-text" th:data-text="#{navbar.darkmode}" th:text="#{navbar.darkmode}"></span>
</a> </a>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
@@ -380,7 +380,7 @@
<span class="material-symbols-rounded"> <span class="material-symbols-rounded">
settings settings
</span> </span>
<span class="icon-text icon-hide tooltip-text" th:data-text="#{navbar.settings}" th:text="#{navbar.settings}"></span> <span class="icon-text icon-hide" th:data-text="#{navbar.settings}" th:text="#{navbar.settings}"></span>
</a> </a>
</li> </li>
</ul> </ul>
@@ -411,7 +411,7 @@
th:title="#{visitGithub}"> th:title="#{visitGithub}">
<img th:src="@{'/images/github.svg'}" alt="github"> <img th:src="@{'/images/github.svg'}" alt="github">
</a> </a>
<a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" target="_blank"th:title="#{seeDockerHub}"> <a href="https://hub.docker.com/r/stirlingtools/stirling-pdf" class="mx-1" role="button" target="_blank"th:title="#{seeDockerHub}">
<img th:src="@{'/images/docker.svg'}" alt="docker"> <img th:src="@{'/images/docker.svg'}" alt="docker">
</a> </a>
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" target="_blank" th:title="#{joinDiscord}"> <a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" target="_blank" th:title="#{joinDiscord}">

View File

@@ -83,9 +83,6 @@
</span> </span>
</button> </button>
</div> </div>
<div class="mb-3">
<button type="button" id="resetFileInputBtn" class="btn btn-danger" onclick="removeAllElements()" th:text="#{reset}">Reset</button>
</div>
<div id="selected-pages-display" class="selected-pages-container hidden"> <div id="selected-pages-display" class="selected-pages-container hidden">
<div style="display:flex; height:3rem; margin-right:1rem"> <div style="display:flex; height:3rem; margin-right:1rem">
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected <h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
@@ -165,4 +162,4 @@
</script> </script>
</body> </body>
</html> </html>

View File

@@ -49,7 +49,7 @@ check_health() {
build_and_test() { build_and_test() {
local version_tag="alpha" local version_tag="alpha"
local dockerfile_name="./Dockerfile" local dockerfile_name="./Dockerfile"
local image_base="frooodle/s-pdf" local image_base="stirlingtools/stirling-pdf"
local security_suffix="" local security_suffix=""
local docker_compose_base="./exampleYmlFiles/docker-compose-latest" local docker_compose_base="./exampleYmlFiles/docker-compose-latest"
local compose_suffix=".yml" local compose_suffix=".yml"