mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2024-11-17 12:40:11 +01:00
Merge branch 'main' into fixed_remove_pages_exception#761
This commit is contained in:
commit
0d5b790443
18
.github/pull_request_template.md
vendored
18
.github/pull_request_template.md
vendored
@ -1,4 +1,18 @@
|
|||||||
# License Agreement for Contributions
|
# Description
|
||||||
By submitting this pull request, I acknowledge and agree that my contributions will be included in Stirling-PDF and that they can be relicensed in the future under MPL 2.0 (Mozilla Public License Version 2.0) license.
|
|
||||||
|
Please provide a summary of the changes, including relevant motivation and context.
|
||||||
|
|
||||||
|
Closes #(issue_number)
|
||||||
|
|
||||||
|
## Checklist:
|
||||||
|
|
||||||
|
- [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
|
||||||
|
- [ ] I have performed a self-review of my own code
|
||||||
|
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||||
|
- [ ] My changes generate no new warnings
|
||||||
|
|
||||||
|
## Contributor License Agreement
|
||||||
|
|
||||||
|
By submitting this pull request, I acknowledge and agree that my contributions will be included in Stirling-PDF and that they can be relicensed in the future under the MPL 2.0 (Mozilla Public License Version 2.0) license.
|
||||||
|
|
||||||
(This does not change the general open-source nature of Stirling-PDF, simply moving from one license to another license)
|
(This does not change the general open-source nature of Stirling-PDF, simply moving from one license to another license)
|
||||||
|
3
.github/workflows/pull_request_template.md
vendored
3
.github/workflows/pull_request_template.md
vendored
@ -1,3 +0,0 @@
|
|||||||
# License Agreement for Contributions
|
|
||||||
By submitting this pull request, I acknowledge and agree that my contributions will be included in Stirling-PDF and that they can be relicensed in the future under MPL 2.0 (Mozilla Public License Version 2.0) license.
|
|
||||||
(This does not change the open-source nature of Stirling-PDF, simply moving from one license to another license)
|
|
2
.github/workflows/releaseArtifacts.yml
vendored
2
.github/workflows/releaseArtifacts.yml
vendored
@ -4,7 +4,7 @@ on:
|
|||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: write
|
||||||
packages: write
|
packages: write
|
||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
|
40
CONTRIBUTING.md
Normal file
40
CONTRIBUTING.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Contributing to Stirling-PDF
|
||||||
|
|
||||||
|
Thank you for your interest in contributing to Stirling-PDF! There are many ways to contribute other than writing code. For example, reporting bugs, creating suggestions, and adding or modifying translations.
|
||||||
|
|
||||||
|
## Issue Guidelines
|
||||||
|
|
||||||
|
Issues can be used to report bugs, request features, or ask questions. If you have a question, you could also ask us in our [Discord](https://discord.gg/FJUSXUSYec).
|
||||||
|
|
||||||
|
Before opening an issue, please check to make sure someone hasn't already opened an issue about it.
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
|
||||||
|
Before you start working on an issue, please comment on (or create) the issue and wait for it to be assigned to you. If someone has already been assigned but didn't have the time to work on it lately, please communicate with them and ask if they're still working on it. This is to avoid multiple people working on the same issue.
|
||||||
|
|
||||||
|
Once you have been assigned an issue, you can start working on it. When you are ready to submit your changes, open a pull request.
|
||||||
|
For a detailed pull request tutorial, see [this guide](https://www.digitalocean.com/community/tutorials/how-to-create-a-pull-request-on-github).
|
||||||
|
|
||||||
|
Please make sure your Pull Request adheres to the following guidelines:
|
||||||
|
|
||||||
|
- Use the PR template provided.
|
||||||
|
- Keep your Pull Request title succinct, detailed and to the point.
|
||||||
|
- Keep commits atomic. One commit should contain one change. If you want to make multiple changes, submit multiple Pull Requests.
|
||||||
|
- Commits should be clear, concise and easy to understand.
|
||||||
|
- References to the Issue number in the Pull Request and/or Commit message.
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
If you would like to add or modify a translation, please see [How to add new languages to Stirling-PDF](HowToAddNewLanguage.md). Also, please create a Pull Request so others can use it!
|
||||||
|
|
||||||
|
## Fixing Bugs or Adding a New Feature
|
||||||
|
|
||||||
|
First, make sure you've read the section [Pull Requests](#pull-requests).
|
||||||
|
|
||||||
|
To build from source, please follow this [Guide](LocalRunGuide.md).
|
||||||
|
|
||||||
|
If, at any point of time, you have a question, please feel free to ask in the same issue thread or in our [Discord](https://discord.gg/FJUSXUSYec).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
By contributing to this project, you agree that your contributions will be licensed under the [GPL 3 License](LICENSE). You also acknowledge and agree that your contributions will be included in Stirling-PDF and that they can be relicensed in the future under the MPL 2.0 (Mozilla Public License Version 2.0) license.
|
@ -6,7 +6,8 @@ FROM ubuntu:latest AS base
|
|||||||
# JDK for app
|
# JDK for app
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
openjdk-17-jre
|
openjdk-17-jre && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Doc conversion
|
# Doc conversion
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
@ -18,7 +19,8 @@ RUN apt-get update && \
|
|||||||
libreoffice-impress \
|
libreoffice-impress \
|
||||||
python3-uno \
|
python3-uno \
|
||||||
curl \
|
curl \
|
||||||
unoconv
|
unoconv && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
# OCR MY PDF (unpaper for descew and other advanced featues)
|
# OCR MY PDF (unpaper for descew and other advanced featues)
|
||||||
@ -30,21 +32,12 @@ apt-get update && \
|
|||||||
python3-pip \
|
python3-pip \
|
||||||
ocrmypdf \
|
ocrmypdf \
|
||||||
unpaper && \
|
unpaper && \
|
||||||
pip install --upgrade pip && \
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
|
mv /usr/share/tesseract-ocr /usr/share/tesseract-ocr-original && \
|
||||||
|
pip install --no-cache-dir --upgrade pip && \
|
||||||
pip install --no-cache-dir --upgrade ocrmypdf && \
|
pip install --no-cache-dir --upgrade ocrmypdf && \
|
||||||
pip install --no-cache-dir --upgrade pillow==10.0.1 reportlab==3.6.13 wheel==0.38.1 setuptools==65.5.1 pyjwt==2.4.0 cryptography==39.0.1
|
pip install --no-cache-dir --upgrade pillow==10.0.1 reportlab==3.6.13 wheel==0.38.1 setuptools==65.5.1 pyjwt==2.4.0 cryptography==39.0.1
|
||||||
|
|
||||||
|
|
||||||
#CV and HTML
|
#CV and HTML
|
||||||
RUN pip install --no-cache-dir opencv-python-headless WeasyPrint
|
RUN pip install --no-cache-dir opencv-python-headless WeasyPrint
|
||||||
|
|
||||||
|
|
||||||
# cleanup and etc
|
|
||||||
RUN rm -rf /var/lib/apt/lists/* && \
|
|
||||||
mkdir /usr/share/tesseract-ocr-original && \
|
|
||||||
cp -r /usr/share/tesseract-ocr/* /usr/share/tesseract-ocr-original && \
|
|
||||||
rm -rf /usr/share/tesseract-ocr
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
41
FolderScanning.md
Normal file
41
FolderScanning.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
## User Guide for Local Directory Scanning and File Processing
|
||||||
|
|
||||||
|
### Whilst Pipelines are in alpha...
|
||||||
|
You must enable this alpha functionality by setting
|
||||||
|
```yaml
|
||||||
|
system:
|
||||||
|
enableAlphaFunctionality: true
|
||||||
|
```
|
||||||
|
To true like in the above for your `/config/settings.yml` file, after restarting Stirling-PDF you should see both UI and folder scanning enabled.
|
||||||
|
|
||||||
|
### Setting Up Watched Folders:
|
||||||
|
- Create a folder where you want your files to be monitored. This is your 'watched folder'.
|
||||||
|
- The default directory for this is `./pipeline/watchedFolders/`
|
||||||
|
- Place any directories you want to be scanned into this folder, this folder should contain multiple folders each for their own tasks and pipelines.
|
||||||
|
|
||||||
|
### Configuring Processing with JSON Files:
|
||||||
|
- In each directory you want processed (e.g `./pipeline/watchedFolders/officePrinter`), include a JSON configuration file.
|
||||||
|
- This JSON file should specify how you want the files in the directory to be handled (e.g., what operations to perform on them) which can be made, configured and downloaded from Stirling-PDF Pipeline interface.r
|
||||||
|
|
||||||
|
### Automatic Scanning and Processing:
|
||||||
|
- The system automatically checks the watched folder every minute for new directories and files to process.
|
||||||
|
- When a directory with a valid JSON configuration file is found, it begins processing the files inside as per the configuration.
|
||||||
|
|
||||||
|
### Processing Steps:
|
||||||
|
- Files in each directory are processed according to the instructions in the JSON file.
|
||||||
|
- This might involve file conversions, data filtering, renaming files, etc. If the output of a step is a zip, this zip will be automatically unzipped as it passes to next process.
|
||||||
|
|
||||||
|
### Results and Output:
|
||||||
|
- After processing, the results are saved in a specified output location. This could be a different folder or location as defined in the JSON file or the default location `./pipeline/finishedFolders/`.
|
||||||
|
- Each processed file is named and organized according to the rules set in the JSON configuration.
|
||||||
|
|
||||||
|
### Completion and Cleanup:
|
||||||
|
- Once processing is complete, the original files in the watched folder's directory are removed.
|
||||||
|
- You can find the processed files in the designated output location.
|
||||||
|
|
||||||
|
### Error Handling:
|
||||||
|
- If there's an error during processing, the system will not delete the original files, allowing you to check and retry if necessary.
|
||||||
|
|
||||||
|
### User Interaction:
|
||||||
|
- As a user, your main tasks are to set up the watched folders, place directories with files for processing, and create the corresponding JSON configuration files.
|
||||||
|
- The system handles the rest, including scanning, processing, and outputting results.
|
@ -16,7 +16,7 @@ If your language isnt represented by a flag just find whichever closely matches
|
|||||||
|
|
||||||
|
|
||||||
For example to add Polish you would add
|
For example to add Polish you would add
|
||||||
```
|
```html
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="pl_PL">
|
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="pl_PL">
|
||||||
<img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski
|
<img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski
|
||||||
</a>
|
</a>
|
||||||
|
42
PipelineFeature.md
Normal file
42
PipelineFeature.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Pipeline Configuration and Usage Tutorial
|
||||||
|
|
||||||
|
## Whilst Pipelines are in alpha...
|
||||||
|
You must enable this alpha functionality by setting
|
||||||
|
```yaml
|
||||||
|
system:
|
||||||
|
enableAlphaFunctionality: true
|
||||||
|
```
|
||||||
|
To true like in the above for your `/config/settings.yml` file, after restarting Stirling-PDF you should see both UI and folder scanning enabled.
|
||||||
|
|
||||||
|
|
||||||
|
## Steps to Configure and Use Your Pipeline
|
||||||
|
|
||||||
|
1. **Access Configuration**
|
||||||
|
- Upon entering the screen, click on the **Configure** button.
|
||||||
|
|
||||||
|
2. **Enter Pipeline Name**
|
||||||
|
- Provide a name for your pipeline in the designated field.
|
||||||
|
|
||||||
|
3. **Select Operations**
|
||||||
|
- Choose the operations for your pipeline (e.g., **Split Pages**), then click **Add Operation**.
|
||||||
|
|
||||||
|
4. **Configure Operation Settings**
|
||||||
|
- Input the necessary settings for each added operation. Settings are highlighted in yellow if customization is needed.
|
||||||
|
|
||||||
|
5. **Add More Operations**
|
||||||
|
- You can add and adjust the order of multiple operations. Ensure each operation's settings are customized.
|
||||||
|
|
||||||
|
6. **Save Settings**
|
||||||
|
- Click **Save Operation Settings** after customizing settings for each operation.
|
||||||
|
|
||||||
|
7. **Validate Pipeline**
|
||||||
|
- Use the **Validation** button to check your pipeline. A green indicator signifies correct setup; a pop-out error indicates issues.
|
||||||
|
|
||||||
|
8. **Download Pipeline Configuration**
|
||||||
|
- To use the configuration for folder scanning (or save it for future use and reupload it), you can also download a JSON file in this menu. You can also pre-load this for future use by placing it in ``/pipeline/defaultWebUIConfigs/``. It will then appear in the dropdown menu for all users to use.
|
||||||
|
|
||||||
|
9. **Submit Files for Processing**
|
||||||
|
- If your pipeline is correctly set up close the configure menu, input the files and hit **Submit**.
|
||||||
|
|
||||||
|
10. **Note on Web UI Limitations**
|
||||||
|
- The current web UI version does not support operations that require multiple different types of inputs, such as adding a separate image to a PDF.
|
123
README.md
123
README.md
@ -16,15 +16,13 @@ Stirling PDF makes no outbound calls for any record keeping or tracking.
|
|||||||
|
|
||||||
All files and PDFs exist either exclusively on the client side, reside in server memory only during task execution, or temporarily reside in a file solely for the execution of the task. Any file downloaded by the user will have been deleted from the server by that point.
|
All files and PDFs exist either exclusively on the client side, reside in server memory only during task execution, or temporarily reside in a file solely for the execution of the task. Any file downloaded by the user will have been deleted from the server by that point.
|
||||||
|
|
||||||
Please feel free to submit feature requests or report bugs either through GitHub issues or on our [Discord](https://discord.gg/Cn8pWhQRxZ)
|
|
||||||
|
|
||||||
![stirling-home](images/stirling-home.png)
|
![stirling-home](images/stirling-home.png)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Dark mode support.
|
- Dark mode support.
|
||||||
- Custom download options (see [here](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/images/settings.png) for example)
|
- Custom download options (see [here](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/images/settings.png) for example)
|
||||||
- Parallel file processing and downloads
|
- Parallel file processing and downloads
|
||||||
- API for integration with external scripts
|
- API for integration with external scripts
|
||||||
- Optional Login and Authentication support (see [here](https://github.com/Stirling-Tools/Stirling-PDF/tree/main#login-authentication) for documentation)
|
- Optional Login and Authentication support (see [here](https://github.com/Stirling-Tools/Stirling-PDF/tree/main#login-authentication) for documentation)
|
||||||
|
|
||||||
|
|
||||||
@ -32,56 +30,56 @@ Please feel free to submit feature requests or report bugs either through GitHub
|
|||||||
|
|
||||||
### **Page Operations**
|
### **Page Operations**
|
||||||
- View and modify PDFs - View multi page PDFs with custom viewing sorting and searching. Plus on page edit features like annotate, draw and adding text and images. (Using PDF.js with Joxit and Liberation.Liberation fonts)
|
- View and modify PDFs - View multi page PDFs with custom viewing sorting and searching. Plus on page edit features like annotate, draw and adding text and images. (Using PDF.js with Joxit and Liberation.Liberation fonts)
|
||||||
- Full interactive GUI for merging/splitting/rotating/moving PDFs and their pages.
|
- Full interactive GUI for merging/splitting/rotating/moving PDFs and their pages.
|
||||||
- Merge multiple PDFs together into a single resultant file.
|
- Merge multiple PDFs together into a single resultant file.
|
||||||
- Split PDFs into multiple files at specified page numbers or extract all pages as individual files.
|
- Split PDFs into multiple files at specified page numbers or extract all pages as individual files.
|
||||||
- Reorganize PDF pages into different orders.
|
- Reorganize PDF pages into different orders.
|
||||||
- Rotate PDFs in 90-degree increments.
|
- Rotate PDFs in 90-degree increments.
|
||||||
- Remove pages.
|
- Remove pages.
|
||||||
- Multi-page layout (Format PDFs into a multi-paged page).
|
- Multi-page layout (Format PDFs into a multi-paged page).
|
||||||
- Scale page contents size by set %.
|
- Scale page contents size by set %.
|
||||||
- Adjust Contrast.
|
- Adjust Contrast.
|
||||||
- Crop PDF.
|
- Crop PDF.
|
||||||
- Auto Split PDF (With physically scanned page dividers).
|
- Auto Split PDF (With physically scanned page dividers).
|
||||||
- Extract page(s).
|
- Extract page(s).
|
||||||
- Convert PDF to a single page.
|
- Convert PDF to a single page.
|
||||||
|
|
||||||
### **Conversion Operations**
|
### **Conversion Operations**
|
||||||
- Convert PDFs to and from images.
|
- Convert PDFs to and from images.
|
||||||
- Convert any common file to PDF (using LibreOffice).
|
- Convert any common file to PDF (using LibreOffice).
|
||||||
- Convert PDF to Word/Powerpoint/Others (using LibreOffice).
|
- Convert PDF to Word/Powerpoint/Others (using LibreOffice).
|
||||||
- Convert HTML to PDF.
|
- Convert HTML to PDF.
|
||||||
- URL to PDF.
|
- URL to PDF.
|
||||||
- Markdown to PDF.
|
- Markdown to PDF.
|
||||||
|
|
||||||
### **Security & Permissions**
|
### **Security & Permissions**
|
||||||
- Add and remove passwords.
|
- Add and remove passwords.
|
||||||
- Change/set PDF Permissions.
|
- Change/set PDF Permissions.
|
||||||
- Add watermark(s).
|
- Add watermark(s).
|
||||||
- Certify/sign PDFs.
|
- Certify/sign PDFs.
|
||||||
- Sanitize PDFs.
|
- Sanitize PDFs.
|
||||||
- Auto-redact text.
|
- Auto-redact text.
|
||||||
|
|
||||||
### **Other Operations**
|
### **Other Operations**
|
||||||
- Add/Generate/Write signatures.
|
- Add/Generate/Write signatures.
|
||||||
- Repair PDFs.
|
- Repair PDFs.
|
||||||
- Detect and remove blank pages.
|
- Detect and remove blank pages.
|
||||||
- Compare 2 PDFs and show differences in text.
|
- Compare 2 PDFs and show differences in text.
|
||||||
- Add images to PDFs.
|
- Add images to PDFs.
|
||||||
- Compress PDFs to decrease their filesize (Using OCRMyPDF).
|
- Compress PDFs to decrease their filesize (Using OCRMyPDF).
|
||||||
- Extract images from PDF.
|
- Extract images from PDF.
|
||||||
- Extract images from Scans.
|
- Extract images from Scans.
|
||||||
- Add page numbers.
|
- Add page numbers.
|
||||||
- Auto rename file by detecting PDF header text.
|
- Auto rename file by detecting PDF header text.
|
||||||
- OCR on PDF (Using OCRMyPDF).
|
- OCR on PDF (Using OCRMyPDF).
|
||||||
- PDF/A conversion (Using OCRMyPDF).
|
- PDF/A conversion (Using OCRMyPDF).
|
||||||
- Edit metadata.
|
- Edit metadata.
|
||||||
- Flatten PDFs.
|
- Flatten PDFs.
|
||||||
- Get all information on a PDF to view or export as JSON.
|
- Get all information on a PDF to view or export as JSON.
|
||||||
|
|
||||||
|
|
||||||
For a overview of the tasks and the technology each uses please view [Endpoint-groups.md](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Endpoint-groups.md)
|
For a overview of the tasks and the technology each uses please view [Endpoint-groups.md](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Endpoint-groups.md)
|
||||||
Hosted instance/demo of the app can be seen [here](https://pdf.adminforge.de/) hosted by the team at adminforge.de
|
Demo of the app is available [here](https://stirlingpdf.io). username: demo, password: demo
|
||||||
|
|
||||||
## Technologies used
|
## Technologies used
|
||||||
- Spring Boot + Thymeleaf
|
- Spring Boot + Thymeleaf
|
||||||
@ -109,7 +107,7 @@ For people that don't mind about space optimization just use the latest tag.
|
|||||||
![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/frooodle/s-pdf/latest-ultra-lite?label=Stirling-PDF%20Ultra-Lite)
|
||||||
|
|
||||||
Docker Run
|
Docker Run
|
||||||
```
|
```bash
|
||||||
docker run -d \
|
docker run -d \
|
||||||
-p 8080:8080 \
|
-p 8080:8080 \
|
||||||
-v /location/of/trainingData:/usr/share/tesseract-ocr/5/tessdata \
|
-v /location/of/trainingData:/usr/share/tesseract-ocr/5/tessdata \
|
||||||
@ -118,14 +116,14 @@ docker run -d \
|
|||||||
-e DOCKER_ENABLE_SECURITY=false \
|
-e DOCKER_ENABLE_SECURITY=false \
|
||||||
--name stirling-pdf \
|
--name stirling-pdf \
|
||||||
frooodle/s-pdf:latest
|
frooodle/s-pdf:latest
|
||||||
|
|
||||||
|
|
||||||
Can also add these for customisation but are not required
|
Can also add these for customisation but are not required
|
||||||
|
|
||||||
-v /location/of/customFiles:/customFiles \
|
-v /location/of/customFiles:/customFiles \
|
||||||
```
|
```
|
||||||
Docker Compose
|
Docker Compose
|
||||||
```
|
```yaml
|
||||||
version: '3.3'
|
version: '3.3'
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
@ -146,7 +144,8 @@ Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "pod
|
|||||||
## Enable OCR/Compression feature
|
## Enable OCR/Compression feature
|
||||||
Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR.md
|
Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR.md
|
||||||
|
|
||||||
## Want to add your own language?
|
## Supported Languages
|
||||||
|
|
||||||
Stirling PDF currently supports 26!
|
Stirling PDF currently supports 26!
|
||||||
- English (English) (en_GB)
|
- English (English) (en_GB)
|
||||||
- English (US) (en_US)
|
- English (US) (en_US)
|
||||||
@ -175,15 +174,9 @@ Stirling PDF currently supports 26!
|
|||||||
- Bulgarian (Български) (bg_BG)
|
- Bulgarian (Български) (bg_BG)
|
||||||
- Sebian Latin alphabet (Srpski) (sr-Latn-RS)
|
- Sebian Latin alphabet (Srpski) (sr-Latn-RS)
|
||||||
|
|
||||||
If you want to add your own language to Stirling-PDF please refer
|
## Contributing (creating issues, translations, fixing bugs, etc.)
|
||||||
https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md
|
|
||||||
|
|
||||||
And please create a PR to merge it back in so others can use it!
|
|
||||||
|
|
||||||
## How to View
|
|
||||||
1. Open a web browser and navigate to `http://localhost:8080/`
|
|
||||||
2. Use the application by following the instructions on the website.
|
|
||||||
|
|
||||||
|
Please see our [Contributing Guide](CONTRIBUTING.md)!
|
||||||
|
|
||||||
## Customisation
|
## Customisation
|
||||||
Stirling PDF allows easy customization of the app.
|
Stirling PDF allows easy customization of the app.
|
||||||
@ -197,7 +190,7 @@ This file is located in the ``/configs`` directory and follows standard YAML for
|
|||||||
|
|
||||||
Environment variables are also supported and would override the settings file
|
Environment variables are also supported and would override the settings file
|
||||||
For example in the settings.yml you have
|
For example in the settings.yml you have
|
||||||
```
|
```yaml
|
||||||
system:
|
system:
|
||||||
defaultLocale: 'en-US'
|
defaultLocale: 'en-US'
|
||||||
```
|
```
|
||||||
@ -205,7 +198,7 @@ system:
|
|||||||
To have this via an environment variable you would have ``SYSTEM_DEFAULTLOCALE``
|
To have this via an environment variable you would have ``SYSTEM_DEFAULTLOCALE``
|
||||||
|
|
||||||
The Current list of settings is
|
The Current list of settings is
|
||||||
```
|
```yaml
|
||||||
security:
|
security:
|
||||||
enableLogin: false # set to 'true' to enable login
|
enableLogin: false # set to 'true' to enable login
|
||||||
csrfDisabled: true
|
csrfDisabled: true
|
||||||
@ -243,9 +236,9 @@ For those wanting to use Stirling-PDFs backend API to link with their own custom
|
|||||||
|
|
||||||
## Login authentication
|
## Login authentication
|
||||||
![stirling-login](images/login-light.png)
|
![stirling-login](images/login-light.png)
|
||||||
### Prerequisites:
|
### Prerequisites:
|
||||||
- User must have the folder ./configs volumed within docker so that it is retained during updates.
|
- User must have the folder ./configs volumed within docker so that it is retained during updates.
|
||||||
- Docker uses must download the security jar version by setting ``DOCKER_ENABLE_SECURITY`` to ``true`` in environment variables.
|
- Docker uses must download the security jar version by setting ``DOCKER_ENABLE_SECURITY`` to ``true`` in environment variables.
|
||||||
- Then either enable login via the settings.yml file or via setting ``SECURITY_ENABLE_LOGIN`` to ``true``
|
- Then either enable login via the settings.yml file or via setting ``SECURITY_ENABLE_LOGIN`` to ``true``
|
||||||
- Now the initial user will be generated with username ``admin`` and password ``stirling``. On login you will be forced to change the password to a new one. You can also use the environment variables ``SECURITY_INITIALLOGIN_USERNAME`` and ``SECURITY_INITIALLOGIN_PASSWORD`` to set your own straight away (Recommended to remove them after user creation).
|
- Now the initial user will be generated with username ``admin`` and password ``stirling``. On login you will be forced to change the password to a new one. You can also use the environment variables ``SECURITY_INITIALLOGIN_USERNAME`` and ``SECURITY_INITIALLOGIN_PASSWORD`` to set your own straight away (Recommended to remove them after user creation).
|
||||||
|
|
||||||
@ -266,10 +259,10 @@ For API usage you must provide a header with 'X-API-Key' and the associated API
|
|||||||
- Progress bar/Tracking
|
- Progress bar/Tracking
|
||||||
- Full custom logic pipelines to combine multiple operations together.
|
- Full custom logic pipelines to combine multiple operations together.
|
||||||
- Folder support with auto scanning to perform operations on
|
- Folder support with auto scanning to perform operations on
|
||||||
- Redact text (Via UI not just automated way)
|
- Redact text (Via UI not just automated way)
|
||||||
- Add Forms
|
- Add Forms
|
||||||
- Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing
|
- Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing
|
||||||
- Fill forms mannual and automatic
|
- Fill forms mannual and automatic
|
||||||
|
|
||||||
### Q2: Why is my application downloading .htm files?
|
### Q2: Why is my application downloading .htm files?
|
||||||
This is an issue caused commonly by your NGINX configuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. ``client_max_body_size SIZE;`` Where "SIZE" is 50M for example for 50MB files.
|
This is an issue caused commonly by your NGINX configuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. ``client_max_body_size SIZE;`` Where "SIZE" is 50M for example for 50MB files.
|
||||||
|
32
build.gradle
32
build.gradle
@ -1,18 +1,18 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.springframework.boot' version '3.2.1'
|
id 'org.springframework.boot' version '3.2.2'
|
||||||
id 'io.spring.dependency-management' version '1.1.3'
|
id 'io.spring.dependency-management' version '1.1.3'
|
||||||
id 'org.springdoc.openapi-gradle-plugin' version '1.8.0'
|
id 'org.springdoc.openapi-gradle-plugin' version '1.8.0'
|
||||||
id "io.swagger.swaggerhub" version "1.3.2"
|
id "io.swagger.swaggerhub" version "1.3.2"
|
||||||
id 'edu.sc.seis.launch4j' version '3.0.5'
|
id 'edu.sc.seis.launch4j' version '3.0.5'
|
||||||
id 'com.diffplug.spotless' version '6.23.3'
|
id 'com.diffplug.spotless' version '6.25.0'
|
||||||
id 'com.github.jk1.dependency-license-report' version '2.5'
|
id 'com.github.jk1.dependency-license-report' version '2.5'
|
||||||
}
|
}
|
||||||
|
|
||||||
import com.github.jk1.license.render.*
|
import com.github.jk1.license.render.*
|
||||||
|
|
||||||
group = 'stirling.software'
|
group = 'stirling.software'
|
||||||
version = '0.19.0'
|
version = '0.20.2'
|
||||||
sourceCompatibility = '17'
|
sourceCompatibility = '17'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@ -91,20 +91,22 @@ dependencies {
|
|||||||
implementation 'ch.qos.logback:logback-core:1.4.14'
|
implementation 'ch.qos.logback:logback-core:1.4.14'
|
||||||
implementation 'org.springframework:spring-webmvc:6.1.2'
|
implementation 'org.springframework:spring-webmvc:6.1.2'
|
||||||
|
|
||||||
|
implementation("io.github.pixee:java-security-toolkit:1.1.2")
|
||||||
|
|
||||||
implementation 'org.yaml:snakeyaml:2.2'
|
implementation 'org.yaml:snakeyaml:2.2'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.1'
|
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.2'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.1'
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.2'
|
||||||
|
|
||||||
if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
|
if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.1'
|
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.2'
|
||||||
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
|
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
|
||||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.1"
|
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.2"
|
||||||
|
|
||||||
//2.2.x requires rebuild of DB file.. need migration path
|
//2.2.x requires rebuild of DB file.. need migration path
|
||||||
implementation "com.h2database:h2:2.1.214"
|
implementation "com.h2database:h2:2.1.214"
|
||||||
}
|
}
|
||||||
|
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.2.1'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.2.2'
|
||||||
|
|
||||||
// Batik
|
// Batik
|
||||||
implementation 'org.apache.xmlgraphics:batik-all:1.17'
|
implementation 'org.apache.xmlgraphics:batik-all:1.17'
|
||||||
@ -137,25 +139,26 @@ dependencies {
|
|||||||
exclude group: 'commons-logging', module: 'commons-logging'
|
exclude group: 'commons-logging', module: 'commons-logging'
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation ('org.apache.pdfbox:pdfbox:2.0.30'){
|
implementation ('org.apache.pdfbox:pdfbox:3.0.1'){
|
||||||
exclude group: 'commons-logging', module: 'commons-logging'
|
exclude group: 'commons-logging', module: 'commons-logging'
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation ('org.apache.pdfbox:xmpbox:2.0.30'){
|
implementation ('org.apache.pdfbox:xmpbox:3.0.1'){
|
||||||
exclude group: 'commons-logging', module: 'commons-logging'
|
exclude group: 'commons-logging', module: 'commons-logging'
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
|
implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
|
||||||
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
|
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
implementation 'org.springframework.boot:spring-boot-starter-actuator:3.2.2'
|
||||||
implementation 'io.micrometer:micrometer-core'
|
implementation 'io.micrometer:micrometer-core:1.12.2'
|
||||||
implementation group: 'com.google.zxing', name: 'core', version: '3.5.2'
|
implementation group: 'com.google.zxing', name: 'core', version: '3.5.2'
|
||||||
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
||||||
implementation 'org.commonmark:commonmark:0.21.0'
|
implementation 'org.commonmark:commonmark:0.21.0'
|
||||||
|
implementation 'org.commonmark:commonmark-ext-gfm-tables:0.21.0'
|
||||||
// https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core
|
// https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core
|
||||||
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'
|
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'
|
||||||
|
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
developmentOnly("org.springframework.boot:spring-boot-devtools:3.2.2")
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.30'
|
compileOnly 'org.projectlombok:lombok:1.18.30'
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.28'
|
annotationProcessor 'org.projectlombok:lombok:1.18.28'
|
||||||
}
|
}
|
||||||
@ -163,6 +166,9 @@ dependencies {
|
|||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
dependsOn 'spotlessApply'
|
dependsOn 'spotlessApply'
|
||||||
}
|
}
|
||||||
|
compileJava {
|
||||||
|
options.compilerArgs << '-parameters'
|
||||||
|
}
|
||||||
|
|
||||||
task writeVersion {
|
task writeVersion {
|
||||||
def propsFile = file('src/main/resources/version.properties')
|
def propsFile = file('src/main/resources/version.properties')
|
||||||
|
@ -21,7 +21,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
SYSTEM_DEFAULTLOCALE: en_US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF-Lite
|
UI_APPNAME: Stirling-PDF-Lite
|
||||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest with Security
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest with Security
|
||||||
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
|
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
|
||||||
|
@ -20,7 +20,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
SYSTEM_DEFAULTLOCALE: en_US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF-Lite
|
UI_APPNAME: Stirling-PDF-Lite
|
||||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest
|
||||||
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
|
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
|
||||||
|
@ -21,7 +21,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
SYSTEM_DEFAULTLOCALE: en_US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF
|
UI_APPNAME: Stirling-PDF
|
||||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security
|
||||||
UI_APPNAMENAVBAR: Stirling-PDF Latest
|
UI_APPNAMENAVBAR: Stirling-PDF Latest
|
||||||
|
@ -21,7 +21,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
SYSTEM_DEFAULTLOCALE: en_US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF-Lite
|
UI_APPNAME: Stirling-PDF-Lite
|
||||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest with Security
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest with Security
|
||||||
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
|
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
|
||||||
|
@ -20,7 +20,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
SYSTEM_DEFAULTLOCALE: en_US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF-Ultra-lite
|
UI_APPNAME: Stirling-PDF-Ultra-lite
|
||||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Ultra-lite Latest
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Ultra-lite Latest
|
||||||
UI_APPNAMENAVBAR: Stirling-PDF-Ultra-lite Latest
|
UI_APPNAMENAVBAR: Stirling-PDF-Ultra-lite Latest
|
||||||
|
@ -21,7 +21,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
SYSTEM_DEFAULTLOCALE: en_US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF
|
UI_APPNAME: Stirling-PDF
|
||||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest
|
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest
|
||||||
UI_APPNAMENAVBAR: Stirling-PDF Latest
|
UI_APPNAMENAVBAR: Stirling-PDF Latest
|
||||||
|
@ -16,7 +16,7 @@ public class PropSync {
|
|||||||
Map<String, String> enProps = linesToProps(enLines);
|
Map<String, String> enProps = linesToProps(enLines);
|
||||||
|
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
if (!file.getName().equals("messages_en_GB.properties")) {
|
if (!"messages_en_GB.properties".equals(file.getName())) {
|
||||||
System.out.println("Processing file: " + file.getName());
|
System.out.println("Processing file: " + file.getName());
|
||||||
List<String> lines;
|
List<String> lines;
|
||||||
try {
|
try {
|
||||||
|
@ -6,6 +6,8 @@ import java.net.Socket;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import io.github.pixee.security.SystemCommand;
|
||||||
|
|
||||||
public class LibreOfficeListener {
|
public class LibreOfficeListener {
|
||||||
|
|
||||||
private static final long ACTIVITY_TIMEOUT = 20 * 60 * 1000; // 20 minutes
|
private static final long ACTIVITY_TIMEOUT = 20 * 60 * 1000; // 20 minutes
|
||||||
@ -44,7 +46,7 @@ public class LibreOfficeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the listener process
|
// Start the listener process
|
||||||
process = Runtime.getRuntime().exec("unoconv --listener");
|
process = SystemCommand.runCommand(Runtime.getRuntime(), "unoconv --listener");
|
||||||
lastActivityTime = System.currentTimeMillis();
|
lastActivityTime = System.currentTimeMillis();
|
||||||
|
|
||||||
// Start a background thread to monitor the activity timeout
|
// Start a background thread to monitor the activity timeout
|
||||||
|
@ -10,6 +10,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
|
import io.github.pixee.security.SystemCommand;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import stirling.software.SPDF.config.ConfigInitializer;
|
import stirling.software.SPDF.config.ConfigInitializer;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
@ -24,7 +26,7 @@ public class SPdfApplication {
|
|||||||
public void init() {
|
public void init() {
|
||||||
// Check if the BROWSER_OPEN environment variable is set to true
|
// Check if the BROWSER_OPEN environment variable is set to true
|
||||||
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
|
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
|
||||||
boolean browserOpen = browserOpenEnv != null && browserOpenEnv.equalsIgnoreCase("true");
|
boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv);
|
||||||
|
|
||||||
if (browserOpen) {
|
if (browserOpen) {
|
||||||
try {
|
try {
|
||||||
@ -34,7 +36,7 @@ public class SPdfApplication {
|
|||||||
Runtime rt = Runtime.getRuntime();
|
Runtime rt = Runtime.getRuntime();
|
||||||
if (os.contains("win")) {
|
if (os.contains("win")) {
|
||||||
// For Windows
|
// For Windows
|
||||||
rt.exec("rundll32 url.dll,FileProtocolHandler " + url);
|
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
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.io.ClassPathResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@ -24,8 +31,15 @@ public class AppConfig {
|
|||||||
|
|
||||||
@Bean(name = "appVersion")
|
@Bean(name = "appVersion")
|
||||||
public String appVersion() {
|
public String appVersion() {
|
||||||
String version = getClass().getPackage().getImplementationVersion();
|
Resource resource = new ClassPathResource("version.properties");
|
||||||
return (version != null) ? version : "0.0.0";
|
Properties props = new Properties();
|
||||||
|
try {
|
||||||
|
props.load(resource.getInputStream());
|
||||||
|
return props.getProperty("version");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return "0.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "homeText")
|
@Bean(name = "homeText")
|
||||||
@ -57,4 +71,22 @@ public class AppConfig {
|
|||||||
if (appName == null) appName = System.getenv("rateLimit");
|
if (appName == null) appName = System.getenv("rateLimit");
|
||||||
return (appName != null) ? Boolean.valueOf(appName) : false;
|
return (appName != null) ? Boolean.valueOf(appName) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean(name = "RunningInDocker")
|
||||||
|
public boolean runningInDocker() {
|
||||||
|
return Files.exists(Paths.get("/.dockerenv"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "bookFormatsInstalled")
|
||||||
|
public boolean bookFormatsInstalled() {
|
||||||
|
return applicationProperties.getSystem().getCustomApplications().isInstallBookFormats();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "htmlFormatsInstalled")
|
||||||
|
public boolean htmlFormatsInstalled() {
|
||||||
|
return applicationProperties
|
||||||
|
.getSystem()
|
||||||
|
.getCustomApplications()
|
||||||
|
.isInstallAdvancedHtmlToPDF();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ public class ConfigInitializer
|
|||||||
for (String line : templateLines) {
|
for (String line : templateLines) {
|
||||||
String key = extractKey.apply(line);
|
String key = extractKey.apply(line);
|
||||||
|
|
||||||
if (line.trim().equalsIgnoreCase("AutomaticallyGenerated:")) {
|
if ("AutomaticallyGenerated:".equalsIgnoreCase(line.trim())) {
|
||||||
insideAutoGenerated = true;
|
insideAutoGenerated = true;
|
||||||
mergedLines.add(line);
|
mergedLines.add(line);
|
||||||
continue;
|
continue;
|
||||||
|
@ -9,11 +9,14 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.DependsOn;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@DependsOn({"bookFormatsInstalled"})
|
||||||
public class EndpointConfiguration {
|
public class EndpointConfiguration {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class);
|
private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class);
|
||||||
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
|
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
|
||||||
@ -21,9 +24,14 @@ public class EndpointConfiguration {
|
|||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
private boolean bookFormatsInstalled;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public EndpointConfiguration(ApplicationProperties applicationProperties) {
|
public EndpointConfiguration(
|
||||||
|
ApplicationProperties applicationProperties,
|
||||||
|
@Qualifier("bookFormatsInstalled") boolean bookFormatsInstalled) {
|
||||||
this.applicationProperties = applicationProperties;
|
this.applicationProperties = applicationProperties;
|
||||||
|
this.bookFormatsInstalled = bookFormatsInstalled;
|
||||||
init();
|
init();
|
||||||
processEnvironmentConfigs();
|
processEnvironmentConfigs();
|
||||||
}
|
}
|
||||||
@ -145,6 +153,12 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("CLI", "ocr-pdf");
|
addEndpointToGroup("CLI", "ocr-pdf");
|
||||||
addEndpointToGroup("CLI", "html-to-pdf");
|
addEndpointToGroup("CLI", "html-to-pdf");
|
||||||
addEndpointToGroup("CLI", "url-to-pdf");
|
addEndpointToGroup("CLI", "url-to-pdf");
|
||||||
|
addEndpointToGroup("CLI", "book-to-pdf");
|
||||||
|
addEndpointToGroup("CLI", "pdf-to-book");
|
||||||
|
|
||||||
|
// Calibre
|
||||||
|
addEndpointToGroup("Calibre", "book-to-pdf");
|
||||||
|
addEndpointToGroup("Calibre", "pdf-to-book");
|
||||||
|
|
||||||
// python
|
// python
|
||||||
addEndpointToGroup("Python", "extract-image-scans");
|
addEndpointToGroup("Python", "extract-image-scans");
|
||||||
@ -215,7 +229,9 @@ public class EndpointConfiguration {
|
|||||||
private void processEnvironmentConfigs() {
|
private void processEnvironmentConfigs() {
|
||||||
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
|
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
|
||||||
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
|
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
|
||||||
|
if (!bookFormatsInstalled) {
|
||||||
|
groupsToRemove.add("Calibre");
|
||||||
|
}
|
||||||
if (endpointsToRemove != null) {
|
if (endpointsToRemove != null) {
|
||||||
for (String endpoint : endpointsToRemove) {
|
for (String endpoint : endpointsToRemove) {
|
||||||
disableEndpoint(endpoint.trim());
|
disableEndpoint(endpoint.trim());
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class PostStartupProcesses {
|
||||||
|
|
||||||
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("RunningInDocker")
|
||||||
|
private boolean runningInDocker;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("bookFormatsInstalled")
|
||||||
|
private boolean bookFormatsInstalled;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("htmlFormatsInstalled")
|
||||||
|
private boolean htmlFormatsInstalled;
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PostStartupProcesses.class);
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void runInstallCommandBasedOnEnvironment() throws IOException, InterruptedException {
|
||||||
|
List<List<String>> commands = new ArrayList<>();
|
||||||
|
// Checking for DOCKER_INSTALL_BOOK_FORMATS environment variable
|
||||||
|
if (bookFormatsInstalled) {
|
||||||
|
List<String> tmpList = new ArrayList<>();
|
||||||
|
// Set up the timezone configuration commands
|
||||||
|
tmpList.addAll(
|
||||||
|
Arrays.asList(
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
"echo 'tzdata tzdata/Areas select Europe' | debconf-set-selections; "
|
||||||
|
+ "echo 'tzdata tzdata/Zones/Europe select Berlin' | debconf-set-selections"));
|
||||||
|
commands.add(tmpList);
|
||||||
|
|
||||||
|
// Install calibre with DEBIAN_FRONTEND set to noninteractive
|
||||||
|
tmpList = new ArrayList<>();
|
||||||
|
tmpList.addAll(
|
||||||
|
Arrays.asList(
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
"DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends calibre"));
|
||||||
|
commands.add(tmpList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking for DOCKER_INSTALL_HTML_FORMATS environment variable
|
||||||
|
if (htmlFormatsInstalled) {
|
||||||
|
List<String> tmpList = new ArrayList<>();
|
||||||
|
// Add -y flag for automatic yes to prompts and --no-install-recommends to reduce size
|
||||||
|
tmpList.addAll(
|
||||||
|
Arrays.asList(
|
||||||
|
"apt-get", "install", "wkhtmltopdf", "-y", "--no-install-recommends"));
|
||||||
|
commands.add(tmpList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!commands.isEmpty()) {
|
||||||
|
// Run the command
|
||||||
|
if (runningInDocker) {
|
||||||
|
List<String> tmpList = new ArrayList<>();
|
||||||
|
tmpList.addAll(Arrays.asList("apt-get", "update"));
|
||||||
|
commands.add(0, tmpList);
|
||||||
|
|
||||||
|
for (List<String> list : commands) {
|
||||||
|
ProcessExecutorResult returnCode =
|
||||||
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.INSTALL_APP, true)
|
||||||
|
.runCommandWithOutputHandling(list);
|
||||||
|
logger.info("RC for app installs {}", returnCode.getRc());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
"Not running inside Docker so skipping automated install process with command.");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (runningInDocker) {
|
||||||
|
logger.info("No custom apps to install.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,14 @@
|
|||||||
package stirling.software.SPDF.controller.api;
|
package stirling.software.SPDF.controller.api;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.multipdf.LayerUtility;
|
import org.apache.pdfbox.multipdf.LayerUtility;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -37,9 +38,7 @@ public class CropController {
|
|||||||
description =
|
description =
|
||||||
"This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")
|
"This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> cropPdf(@ModelAttribute CropPdfForm form) throws IOException {
|
public ResponseEntity<byte[]> cropPdf(@ModelAttribute CropPdfForm form) throws IOException {
|
||||||
|
PDDocument sourceDocument = Loader.loadPDF(form.getFileInput().getBytes());
|
||||||
PDDocument sourceDocument =
|
|
||||||
PDDocument.load(new ByteArrayInputStream(form.getFileInput().getBytes()));
|
|
||||||
|
|
||||||
PDDocument newDocument = new PDDocument();
|
PDDocument newDocument = new PDDocument();
|
||||||
|
|
||||||
@ -53,7 +52,8 @@ public class CropController {
|
|||||||
// Create a new page with the size of the source page
|
// Create a new page with the size of the source page
|
||||||
PDPage newPage = new PDPage(sourcePage.getMediaBox());
|
PDPage newPage = new PDPage(sourcePage.getMediaBox());
|
||||||
newDocument.addPage(newPage);
|
newDocument.addPage(newPage);
|
||||||
PDPageContentStream contentStream = new PDPageContentStream(newDocument, newPage);
|
PDPageContentStream contentStream =
|
||||||
|
new PDPageContentStream(newDocument, newPage, AppendMode.OVERWRITE, true, true);
|
||||||
|
|
||||||
// Import the source page as a form XObject
|
// Import the source page as a form XObject
|
||||||
PDFormXObject formXObject = layerUtility.importPageAsForm(sourceDocument, i);
|
PDFormXObject formXObject = layerUtility.importPageAsForm(sourceDocument, i);
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
package stirling.software.SPDF.controller.api;
|
package stirling.software.SPDF.controller.api;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.pdfbox.io.MemoryUsageSetting;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.multipdf.PDFMergerUtility;
|
import org.apache.pdfbox.multipdf.PDFMergerUtility;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
@ -27,6 +28,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
|
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
|
||||||
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -84,8 +86,8 @@ public class MergeController {
|
|||||||
};
|
};
|
||||||
case "byPDFTitle":
|
case "byPDFTitle":
|
||||||
return (file1, file2) -> {
|
return (file1, file2) -> {
|
||||||
try (PDDocument doc1 = PDDocument.load(file1.getInputStream());
|
try (PDDocument doc1 = Loader.loadPDF(file1.getBytes());
|
||||||
PDDocument doc2 = PDDocument.load(file2.getInputStream())) {
|
PDDocument doc2 = Loader.loadPDF(file2.getBytes())) {
|
||||||
String title1 = doc1.getDocumentInformation().getTitle();
|
String title1 = doc1.getDocumentInformation().getTitle();
|
||||||
String title2 = doc2.getDocumentInformation().getTitle();
|
String title2 = doc2.getDocumentInformation().getTitle();
|
||||||
return title1.compareTo(title2);
|
return title1.compareTo(title2);
|
||||||
@ -106,6 +108,7 @@ public class MergeController {
|
|||||||
"This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided. Input:PDF Output:PDF Type:MISO")
|
"This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided. Input:PDF Output:PDF Type:MISO")
|
||||||
public ResponseEntity<byte[]> mergePdfs(@ModelAttribute MergePdfsRequest form)
|
public ResponseEntity<byte[]> mergePdfs(@ModelAttribute MergePdfsRequest form)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
List<File> filesToDelete = new ArrayList<File>();
|
||||||
try {
|
try {
|
||||||
MultipartFile[] files = form.getFileInput();
|
MultipartFile[] files = form.getFileInput();
|
||||||
Arrays.sort(files, getSortComparator(form.getSortType()));
|
Arrays.sort(files, getSortComparator(form.getSortType()));
|
||||||
@ -113,20 +116,27 @@ public class MergeController {
|
|||||||
PDFMergerUtility mergedDoc = new PDFMergerUtility();
|
PDFMergerUtility mergedDoc = new PDFMergerUtility();
|
||||||
ByteArrayOutputStream docOutputstream = new ByteArrayOutputStream();
|
ByteArrayOutputStream docOutputstream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
for (MultipartFile file : files) {
|
for (MultipartFile multipartFile : files) {
|
||||||
mergedDoc.addSource(new ByteArrayInputStream(file.getBytes()));
|
File tempFile = GeneralUtils.convertMultipartFileToFile(multipartFile);
|
||||||
|
filesToDelete.add(tempFile);
|
||||||
|
mergedDoc.addSource(tempFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedDoc.setDestinationFileName(
|
mergedDoc.setDestinationFileName(
|
||||||
files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf");
|
files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_merged.pdf");
|
||||||
mergedDoc.setDestinationStream(docOutputstream);
|
mergedDoc.setDestinationStream(docOutputstream);
|
||||||
mergedDoc.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
|
|
||||||
|
mergedDoc.mergeDocuments(null);
|
||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
docOutputstream.toByteArray(), mergedDoc.getDestinationFileName());
|
docOutputstream.toByteArray(), mergedDoc.getDestinationFileName());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Error in merge pdf process", ex);
|
logger.error("Error in merge pdf process", ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
|
} finally {
|
||||||
|
for (File file : filesToDelete) {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import java.awt.Color;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.multipdf.LayerUtility;
|
import org.apache.pdfbox.multipdf.LayerUtility;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
@ -20,6 +21,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -57,7 +59,7 @@ public class MultiPageLayoutController {
|
|||||||
: (int) Math.sqrt(pagesPerSheet);
|
: (int) Math.sqrt(pagesPerSheet);
|
||||||
int rows = pagesPerSheet == 2 || pagesPerSheet == 3 ? 1 : (int) Math.sqrt(pagesPerSheet);
|
int rows = pagesPerSheet == 2 || pagesPerSheet == 3 ? 1 : (int) Math.sqrt(pagesPerSheet);
|
||||||
|
|
||||||
PDDocument sourceDocument = PDDocument.load(file.getInputStream());
|
PDDocument sourceDocument = Loader.loadPDF(file.getBytes());
|
||||||
PDDocument newDocument = new PDDocument();
|
PDDocument newDocument = new PDDocument();
|
||||||
PDPage newPage = new PDPage(PDRectangle.A4);
|
PDPage newPage = new PDPage(PDRectangle.A4);
|
||||||
newDocument.addPage(newPage);
|
newDocument.addPage(newPage);
|
||||||
@ -135,6 +137,7 @@ public class MultiPageLayoutController {
|
|||||||
byte[] result = baos.toByteArray();
|
byte[] result = baos.toByteArray();
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
result,
|
result,
|
||||||
file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_layoutChanged.pdf");
|
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_layoutChanged.pdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,13 @@ package stirling.software.SPDF.controller.api;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.multipdf.Overlay;
|
import org.apache.pdfbox.multipdf.Overlay;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -18,6 +20,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -53,7 +56,7 @@ public class PdfOverlayController {
|
|||||||
// "FixedRepeatOverlay"
|
// "FixedRepeatOverlay"
|
||||||
int[] counts = request.getCounts(); // Used for FixedRepeatOverlay mode
|
int[] counts = request.getCounts(); // Used for FixedRepeatOverlay mode
|
||||||
|
|
||||||
try (PDDocument basePdf = PDDocument.load(baseFile.getInputStream());
|
try (PDDocument basePdf = Loader.loadPDF(baseFile.getBytes());
|
||||||
Overlay overlay = new Overlay()) {
|
Overlay overlay = new Overlay()) {
|
||||||
Map<Integer, String> overlayGuide =
|
Map<Integer, String> overlayGuide =
|
||||||
prepareOverlayGuide(
|
prepareOverlayGuide(
|
||||||
@ -74,7 +77,8 @@ public class PdfOverlayController {
|
|||||||
overlay.overlay(overlayGuide).save(outputStream);
|
overlay.overlay(overlayGuide).save(outputStream);
|
||||||
byte[] data = outputStream.toByteArray();
|
byte[] data = outputStream.toByteArray();
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
baseFile.getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
Filenames.toSimpleFileName(baseFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_overlayed.pdf"; // Remove file extension and append .pdf
|
+ "_overlayed.pdf"; // Remove file extension and append .pdf
|
||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
@ -131,10 +135,10 @@ public class PdfOverlayController {
|
|||||||
overlayFileIndex = (overlayFileIndex + 1) % overlayFiles.length;
|
overlayFileIndex = (overlayFileIndex + 1) % overlayFiles.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (PDDocument overlayPdf = PDDocument.load(overlayFiles[overlayFileIndex])) {
|
try (PDDocument overlayPdf = Loader.loadPDF(overlayFiles[overlayFileIndex])) {
|
||||||
PDDocument singlePageDocument = new PDDocument();
|
PDDocument singlePageDocument = new PDDocument();
|
||||||
singlePageDocument.addPage(overlayPdf.getPage(pageCountInCurrentOverlay));
|
singlePageDocument.addPage(overlayPdf.getPage(pageCountInCurrentOverlay));
|
||||||
File tempFile = File.createTempFile("overlay-page-", ".pdf");
|
File tempFile = Files.createTempFile("overlay-page-", ".pdf").toFile();
|
||||||
singlePageDocument.save(tempFile);
|
singlePageDocument.save(tempFile);
|
||||||
singlePageDocument.close();
|
singlePageDocument.close();
|
||||||
|
|
||||||
@ -147,7 +151,7 @@ public class PdfOverlayController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getNumberOfPages(File file) throws IOException {
|
private int getNumberOfPages(File file) throws IOException {
|
||||||
try (PDDocument doc = PDDocument.load(file)) {
|
try (PDDocument doc = Loader.loadPDF(file)) {
|
||||||
return doc.getNumberOfPages();
|
return doc.getNumberOfPages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +163,7 @@ public class PdfOverlayController {
|
|||||||
File overlayFile = overlayFiles[(basePageIndex - 1) % overlayFiles.length];
|
File overlayFile = overlayFiles[(basePageIndex - 1) % overlayFiles.length];
|
||||||
|
|
||||||
// Load the overlay document to check its page count
|
// Load the overlay document to check its page count
|
||||||
try (PDDocument overlayPdf = PDDocument.load(overlayFile)) {
|
try (PDDocument overlayPdf = Loader.loadPDF(overlayFile)) {
|
||||||
int overlayPageCount = overlayPdf.getNumberOfPages();
|
int overlayPageCount = overlayPdf.getNumberOfPages();
|
||||||
if ((basePageIndex - 1) % overlayPageCount < overlayPageCount) {
|
if ((basePageIndex - 1) % overlayPageCount < overlayPageCount) {
|
||||||
overlayGuide.put(basePageIndex, overlayFile.getAbsolutePath());
|
overlayGuide.put(basePageIndex, overlayFile.getAbsolutePath());
|
||||||
@ -181,7 +185,7 @@ public class PdfOverlayController {
|
|||||||
int repeatCount = counts[i];
|
int repeatCount = counts[i];
|
||||||
|
|
||||||
// Load the overlay document to check its page count
|
// Load the overlay document to check its page count
|
||||||
try (PDDocument overlayPdf = PDDocument.load(overlayFile)) {
|
try (PDDocument overlayPdf = Loader.loadPDF(overlayFile)) {
|
||||||
int overlayPageCount = overlayPdf.getNumberOfPages();
|
int overlayPageCount = overlayPdf.getNumberOfPages();
|
||||||
for (int j = 0; j < repeatCount; j++) {
|
for (int j = 0; j < repeatCount; j++) {
|
||||||
for (int page = 0; page < overlayPageCount; page++) {
|
for (int page = 0; page < overlayPageCount; page++) {
|
||||||
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -15,6 +16,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ public class RearrangePagesPDFController {
|
|||||||
MultipartFile pdfFile = request.getFileInput();
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
String pagesToDelete = request.getPageNumbers();
|
String pagesToDelete = request.getPageNumbers();
|
||||||
|
|
||||||
PDDocument document = PDDocument.load(pdfFile.getBytes());
|
PDDocument document = Loader.loadPDF(pdfFile.getBytes());
|
||||||
|
|
||||||
// Split the page order string into an array of page numbers or range of numbers
|
// Split the page order string into an array of page numbers or range of numbers
|
||||||
String[] pageOrderArr = pagesToDelete.split(",");
|
String[] pageOrderArr = pagesToDelete.split(",");
|
||||||
@ -56,7 +58,9 @@ public class RearrangePagesPDFController {
|
|||||||
}
|
}
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_removed_pages.pdf");
|
Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_removed_pages.pdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Integer> removeFirst(int totalPages) {
|
private List<Integer> removeFirst(int totalPages) {
|
||||||
@ -179,7 +183,7 @@ public class RearrangePagesPDFController {
|
|||||||
String sortType = request.getCustomMode();
|
String sortType = request.getCustomMode();
|
||||||
try {
|
try {
|
||||||
// Load the input PDF
|
// Load the input PDF
|
||||||
PDDocument document = PDDocument.load(pdfFile.getInputStream());
|
PDDocument document = Loader.loadPDF(pdfFile.getBytes());
|
||||||
|
|
||||||
// Split the page order string into an array of page numbers or range of numbers
|
// Split the page order string into an array of page numbers or range of numbers
|
||||||
String[] pageOrderArr = pageOrder != null ? pageOrder.split(",") : new String[0];
|
String[] pageOrderArr = pageOrder != null ? pageOrder.split(",") : new String[0];
|
||||||
@ -210,7 +214,8 @@ public class RearrangePagesPDFController {
|
|||||||
|
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_rearranged.pdf");
|
+ "_rearranged.pdf");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("Failed rearranging documents", e);
|
logger.error("Failed rearranging documents", e);
|
||||||
|
@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.api;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||||
@ -14,6 +15,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -37,7 +39,7 @@ public class RotationController {
|
|||||||
MultipartFile pdfFile = request.getFileInput();
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
Integer angle = request.getAngle();
|
Integer angle = request.getAngle();
|
||||||
// Load the PDF document
|
// Load the PDF document
|
||||||
PDDocument document = PDDocument.load(pdfFile.getBytes());
|
PDDocument document = Loader.loadPDF(pdfFile.getBytes());
|
||||||
|
|
||||||
// Get the list of pages in the document
|
// Get the list of pages in the document
|
||||||
PDPageTree pages = document.getPages();
|
PDPageTree pages = document.getPages();
|
||||||
@ -48,6 +50,8 @@ public class RotationController {
|
|||||||
|
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rotated.pdf");
|
Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_rotated.pdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import java.io.IOException;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.multipdf.LayerUtility;
|
import org.apache.pdfbox.multipdf.LayerUtility;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
@ -21,6 +22,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ public class ScalePagesController {
|
|||||||
|
|
||||||
PDRectangle targetSize = sizeMap.get(targetPDRectangle);
|
PDRectangle targetSize = sizeMap.get(targetPDRectangle);
|
||||||
|
|
||||||
PDDocument sourceDocument = PDDocument.load(file.getBytes());
|
PDDocument sourceDocument = Loader.loadPDF(file.getBytes());
|
||||||
PDDocument outputDocument = new PDDocument();
|
PDDocument outputDocument = new PDDocument();
|
||||||
|
|
||||||
int totalPages = sourceDocument.getNumberOfPages();
|
int totalPages = sourceDocument.getNumberOfPages();
|
||||||
@ -83,7 +85,11 @@ public class ScalePagesController {
|
|||||||
|
|
||||||
PDPageContentStream contentStream =
|
PDPageContentStream contentStream =
|
||||||
new PDPageContentStream(
|
new PDPageContentStream(
|
||||||
outputDocument, newPage, PDPageContentStream.AppendMode.APPEND, true);
|
outputDocument,
|
||||||
|
newPage,
|
||||||
|
PDPageContentStream.AppendMode.APPEND,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
|
||||||
float x = (targetSize.getWidth() - sourceSize.getWidth() * scale) / 2;
|
float x = (targetSize.getWidth() - sourceSize.getWidth() * scale) / 2;
|
||||||
float y = (targetSize.getHeight() - sourceSize.getHeight() * scale) / 2;
|
float y = (targetSize.getHeight() - sourceSize.getHeight() * scale) / 2;
|
||||||
@ -107,6 +113,7 @@ public class ScalePagesController {
|
|||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
baos.toByteArray(),
|
baos.toByteArray(),
|
||||||
file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_scaled.pdf");
|
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_scaled.pdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package stirling.software.SPDF.controller.api;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -11,6 +10,7 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -23,6 +23,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -46,8 +47,8 @@ public class SplitPDFController {
|
|||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
String pages = request.getPageNumbers();
|
String pages = request.getPageNumbers();
|
||||||
// open the pdf document
|
// open the pdf document
|
||||||
InputStream inputStream = file.getInputStream();
|
|
||||||
PDDocument document = PDDocument.load(inputStream);
|
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||||
|
|
||||||
List<Integer> pageNumbers = request.getPageNumbersList(document);
|
List<Integer> pageNumbers = request.getPageNumbersList(document);
|
||||||
if (!pageNumbers.contains(document.getNumberOfPages() - 1))
|
if (!pageNumbers.contains(document.getNumberOfPages() - 1))
|
||||||
@ -83,7 +84,9 @@ public class SplitPDFController {
|
|||||||
|
|
||||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
||||||
|
|
||||||
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
|
String filename =
|
||||||
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "");
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
||||||
// loop through the split documents and write them to the zip file
|
// loop through the split documents and write them to the zip file
|
||||||
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
||||||
|
@ -9,10 +9,12 @@ import java.util.List;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.multipdf.LayerUtility;
|
import org.apache.pdfbox.multipdf.LayerUtility;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
import org.apache.pdfbox.util.Matrix;
|
import org.apache.pdfbox.util.Matrix;
|
||||||
@ -24,6 +26,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -45,7 +48,7 @@ public class SplitPdfBySectionsController {
|
|||||||
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
||||||
|
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
PDDocument sourceDocument = PDDocument.load(file.getInputStream());
|
PDDocument sourceDocument = Loader.loadPDF(file.getBytes());
|
||||||
|
|
||||||
// Process the PDF based on split parameters
|
// Process the PDF based on split parameters
|
||||||
int horiz = request.getHorizontalDivisions() + 1;
|
int horiz = request.getHorizontalDivisions() + 1;
|
||||||
@ -62,7 +65,9 @@ public class SplitPdfBySectionsController {
|
|||||||
sourceDocument.close();
|
sourceDocument.close();
|
||||||
|
|
||||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
||||||
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
|
String filename =
|
||||||
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "");
|
||||||
byte[] data;
|
byte[] data;
|
||||||
|
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
||||||
@ -115,13 +120,13 @@ public class SplitPdfBySectionsController {
|
|||||||
document, document.getPages().indexOf(originalPage));
|
document, document.getPages().indexOf(originalPage));
|
||||||
|
|
||||||
try (PDPageContentStream contentStream =
|
try (PDPageContentStream contentStream =
|
||||||
new PDPageContentStream(subDoc, subPage)) {
|
new PDPageContentStream(
|
||||||
|
subDoc, subPage, AppendMode.APPEND, true, true)) {
|
||||||
// Set clipping area and position
|
// Set clipping area and position
|
||||||
float translateX = -subPageWidth * i;
|
float translateX = -subPageWidth * i;
|
||||||
float translateY = height - subPageHeight * (verticalDivisions - j);
|
|
||||||
|
|
||||||
// Code for google Docs pdfs..
|
// float translateY = height - subPageHeight * (verticalDivisions - j);
|
||||||
// float translateY = -subPageHeight * (verticalDivisions - 1 - j);
|
float translateY = -subPageHeight * (verticalDivisions - 1 - j);
|
||||||
|
|
||||||
contentStream.saveGraphicsState();
|
contentStream.saveGraphicsState();
|
||||||
contentStream.addRect(0, 0, subPageWidth, subPageHeight);
|
contentStream.addRect(0, 0, subPageWidth, subPageHeight);
|
||||||
|
@ -9,6 +9,7 @@ import java.util.List;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -19,6 +20,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ public class SplitPdfBySizeController {
|
|||||||
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<ByteArrayOutputStream>();
|
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<ByteArrayOutputStream>();
|
||||||
|
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
PDDocument sourceDocument = PDDocument.load(file.getInputStream());
|
PDDocument sourceDocument = Loader.loadPDF(file.getBytes());
|
||||||
|
|
||||||
// 0 = size, 1 = page count, 2 = doc count
|
// 0 = size, 1 = page count, 2 = doc count
|
||||||
int type = request.getSplitType();
|
int type = request.getSplitType();
|
||||||
@ -119,7 +121,9 @@ public class SplitPdfBySizeController {
|
|||||||
sourceDocument.close();
|
sourceDocument.close();
|
||||||
|
|
||||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
||||||
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
|
String filename =
|
||||||
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "");
|
||||||
byte[] data;
|
byte[] data;
|
||||||
|
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
||||||
|
@ -4,6 +4,7 @@ import java.awt.geom.AffineTransform;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.multipdf.LayerUtility;
|
import org.apache.pdfbox.multipdf.LayerUtility;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
@ -40,7 +41,7 @@ public class ToSinglePageController {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
// Load the source document
|
// Load the source document
|
||||||
PDDocument sourceDocument = PDDocument.load(request.getFileInput().getInputStream());
|
PDDocument sourceDocument = Loader.loadPDF(request.getFileInput().getBytes());
|
||||||
|
|
||||||
// Calculate total height and max width
|
// Calculate total height and max width
|
||||||
float totalHeight = 0;
|
float totalHeight = 0;
|
||||||
|
@ -13,6 +13,7 @@ import org.springframework.security.core.Authentication;
|
|||||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
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;
|
||||||
@ -20,13 +21,18 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||||
import org.springframework.web.servlet.view.RedirectView;
|
import org.springframework.web.servlet.view.RedirectView;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
import stirling.software.SPDF.model.Role;
|
import stirling.software.SPDF.model.Role;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
|
import stirling.software.SPDF.model.api.user.UpdateUserDetails;
|
||||||
|
import stirling.software.SPDF.model.api.user.UsernameAndPass;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
|
@Tag(name = "User", description = "User APIs")
|
||||||
@RequestMapping("/api/v1/user")
|
@RequestMapping("/api/v1/user")
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
@ -34,14 +40,13 @@ public class UserController {
|
|||||||
|
|
||||||
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
|
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
public String register(
|
public String register(@ModelAttribute UsernameAndPass requestModel, Model model) {
|
||||||
@RequestParam String username, @RequestParam String password, Model model) {
|
if (userService.usernameExists(requestModel.getUsername())) {
|
||||||
if (userService.usernameExists(username)) {
|
|
||||||
model.addAttribute("error", "Username already exists");
|
model.addAttribute("error", "Username already exists");
|
||||||
return "register";
|
return "register";
|
||||||
}
|
}
|
||||||
|
|
||||||
userService.saveUser(username, password);
|
userService.saveUser(requestModel.getUsername(), requestModel.getPassword());
|
||||||
return "redirect:/login?registered=true";
|
return "redirect:/login?registered=true";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,12 +54,15 @@ public class UserController {
|
|||||||
@PostMapping("/change-username-and-password")
|
@PostMapping("/change-username-and-password")
|
||||||
public RedirectView changeUsernameAndPassword(
|
public RedirectView changeUsernameAndPassword(
|
||||||
Principal principal,
|
Principal principal,
|
||||||
@RequestParam String currentPassword,
|
@ModelAttribute UpdateUserDetails requestModel,
|
||||||
@RequestParam String newUsername,
|
|
||||||
@RequestParam String newPassword,
|
|
||||||
HttpServletRequest request,
|
HttpServletRequest request,
|
||||||
HttpServletResponse response,
|
HttpServletResponse response,
|
||||||
RedirectAttributes redirectAttributes) {
|
RedirectAttributes redirectAttributes) {
|
||||||
|
|
||||||
|
String currentPassword = requestModel.getPassword();
|
||||||
|
String newPassword = requestModel.getNewPassword();
|
||||||
|
String newUsername = requestModel.getNewUsername();
|
||||||
|
|
||||||
if (principal == null) {
|
if (principal == null) {
|
||||||
return new RedirectView("/change-creds?messageType=notAuthenticated");
|
return new RedirectView("/change-creds?messageType=notAuthenticated");
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
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.github.pixee.security.Filenames;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.GeneralFile;
|
||||||
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
@RequestMapping("/api/v1/convert")
|
||||||
|
public class ConvertBookToPDFController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("bookFormatsInstalled")
|
||||||
|
private boolean bookFormatsInstalled;
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/book/pdf")
|
||||||
|
@Operation(
|
||||||
|
summary =
|
||||||
|
"Convert a BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) to PDF",
|
||||||
|
description =
|
||||||
|
"(Requires bookFormatsInstalled flag and Calibre installed) This endpoint takes an BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) input and converts it to PDF format.")
|
||||||
|
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute GeneralFile request) throws Exception {
|
||||||
|
MultipartFile fileInput = request.getFileInput();
|
||||||
|
|
||||||
|
if (!bookFormatsInstalled) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"bookFormatsInstalled flag is False, this functionality is not avaiable");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileInput == null) {
|
||||||
|
throw new IllegalArgumentException("Please provide a file for conversion.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String originalFilename = Filenames.toSimpleFileName(fileInput.getOriginalFilename());
|
||||||
|
|
||||||
|
if (originalFilename != null) {
|
||||||
|
String originalFilenameLower = originalFilename.toLowerCase();
|
||||||
|
if (!originalFilenameLower.endsWith(".epub")
|
||||||
|
&& !originalFilenameLower.endsWith(".mobi")
|
||||||
|
&& !originalFilenameLower.endsWith(".azw3")
|
||||||
|
&& !originalFilenameLower.endsWith(".fb2")
|
||||||
|
&& !originalFilenameLower.endsWith(".txt")
|
||||||
|
&& !originalFilenameLower.endsWith(".docx")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"File must be in .epub, .mobi, .azw3, .fb2, .txt, or .docx format.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] pdfBytes = FileToPdf.convertBookTypeToPdf(fileInput.getBytes(), originalFilename);
|
||||||
|
|
||||||
|
String outputFilename =
|
||||||
|
originalFilename.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ ".pdf"; // Remove file extension and append .pdf
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package stirling.software.SPDF.controller.api.converters;
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
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;
|
||||||
@ -7,10 +9,11 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.GeneralFile;
|
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
|
||||||
import stirling.software.SPDF.utils.FileToPdf;
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -19,12 +22,17 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertHtmlToPDF {
|
public class ConvertHtmlToPDF {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("htmlFormatsInstalled")
|
||||||
|
private boolean htmlFormatsInstalled;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
|
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
|
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
|
||||||
description =
|
description =
|
||||||
"This endpoint takes an HTML or ZIP file input and converts it to a PDF format.")
|
"This endpoint takes an HTML or ZIP file input and converts it to a PDF format.")
|
||||||
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute GeneralFile request) throws Exception {
|
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute HTMLToPdfRequest request)
|
||||||
|
throws Exception {
|
||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
|
|
||||||
if (fileInput == null) {
|
if (fileInput == null) {
|
||||||
@ -32,12 +40,14 @@ public class ConvertHtmlToPDF {
|
|||||||
"Please provide an HTML or ZIP file for conversion.");
|
"Please provide an HTML or ZIP file for conversion.");
|
||||||
}
|
}
|
||||||
|
|
||||||
String originalFilename = fileInput.getOriginalFilename();
|
String originalFilename = Filenames.toSimpleFileName(fileInput.getOriginalFilename());
|
||||||
if (originalFilename == null
|
if (originalFilename == null
|
||||||
|| (!originalFilename.endsWith(".html") && !originalFilename.endsWith(".zip"))) {
|
|| (!originalFilename.endsWith(".html") && !originalFilename.endsWith(".zip"))) {
|
||||||
throw new IllegalArgumentException("File must be either .html or .zip format.");
|
throw new IllegalArgumentException("File must be either .html or .zip format.");
|
||||||
}
|
}
|
||||||
byte[] pdfBytes = FileToPdf.convertHtmlToPdf(fileInput.getBytes(), originalFilename);
|
byte[] pdfBytes =
|
||||||
|
FileToPdf.convertHtmlToPdf(
|
||||||
|
request, fileInput.getBytes(), originalFilename, htmlFormatsInstalled);
|
||||||
|
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
originalFilename.replaceFirst("[.][^.]+$", "")
|
originalFilename.replaceFirst("[.][^.]+$", "")
|
||||||
|
@ -18,6 +18,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -54,9 +55,11 @@ public class ConvertImgPDFController {
|
|||||||
colorTypeResult = ImageType.BINARY;
|
colorTypeResult = ImageType.BINARY;
|
||||||
}
|
}
|
||||||
// returns bytes for image
|
// returns bytes for image
|
||||||
boolean singleImage = singleOrMultiple.equals("single");
|
boolean singleImage = "single".equals(singleOrMultiple);
|
||||||
byte[] result = null;
|
byte[] result = null;
|
||||||
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
|
String filename =
|
||||||
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "");
|
||||||
try {
|
try {
|
||||||
result =
|
result =
|
||||||
PdfUtils.convertFromPdf(
|
PdfUtils.convertFromPdf(
|
||||||
@ -96,7 +99,7 @@ public class ConvertImgPDFController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert images to a PDF file",
|
summary = "Convert images to a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images. Input:Image Output:PDF Type:SISO?")
|
"This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images. Input:Image Output:PDF Type:MISO")
|
||||||
public ResponseEntity<byte[]> convertToPdf(@ModelAttribute ConvertToPdfRequest request)
|
public ResponseEntity<byte[]> convertToPdf(@ModelAttribute ConvertToPdfRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile[] file = request.getFileInput();
|
MultipartFile[] file = request.getFileInput();
|
||||||
@ -113,6 +116,6 @@ public class ConvertImgPDFController {
|
|||||||
|
|
||||||
private String getMediaType(String imageFormat) {
|
private String getMediaType(String imageFormat) {
|
||||||
String mimeType = URLConnection.guessContentTypeFromName("." + imageFormat);
|
String mimeType = URLConnection.guessContentTypeFromName("." + imageFormat);
|
||||||
return mimeType.equals("null") ? "application/octet-stream" : mimeType;
|
return "null".equals(mimeType) ? "application/octet-stream" : mimeType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
package stirling.software.SPDF.controller.api.converters;
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.commonmark.Extension;
|
||||||
|
import org.commonmark.ext.gfm.tables.TableBlock;
|
||||||
|
import org.commonmark.ext.gfm.tables.TablesExtension;
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
import org.commonmark.parser.Parser;
|
import org.commonmark.parser.Parser;
|
||||||
|
import org.commonmark.renderer.html.AttributeProvider;
|
||||||
import org.commonmark.renderer.html.HtmlRenderer;
|
import org.commonmark.renderer.html.HtmlRenderer;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
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;
|
||||||
@ -10,6 +19,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -22,11 +32,15 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertMarkdownToPdf {
|
public class ConvertMarkdownToPdf {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("htmlFormatsInstalled")
|
||||||
|
private boolean htmlFormatsInstalled;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
|
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a Markdown file to PDF",
|
summary = "Convert a Markdown file to PDF",
|
||||||
description =
|
description =
|
||||||
"This endpoint takes a Markdown file input, converts it to HTML, and then to PDF format.")
|
"This endpoint takes a Markdown file input, converts it to HTML, and then to PDF format. Input:MARKDOWN Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> markdownToPdf(@ModelAttribute GeneralFile request)
|
public ResponseEntity<byte[]> markdownToPdf(@ModelAttribute GeneralFile request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
@ -35,18 +49,27 @@ public class ConvertMarkdownToPdf {
|
|||||||
throw new IllegalArgumentException("Please provide a Markdown file for conversion.");
|
throw new IllegalArgumentException("Please provide a Markdown file for conversion.");
|
||||||
}
|
}
|
||||||
|
|
||||||
String originalFilename = fileInput.getOriginalFilename();
|
String originalFilename = Filenames.toSimpleFileName(fileInput.getOriginalFilename());
|
||||||
if (originalFilename == null || !originalFilename.endsWith(".md")) {
|
if (originalFilename == null || !originalFilename.endsWith(".md")) {
|
||||||
throw new IllegalArgumentException("File must be in .md format.");
|
throw new IllegalArgumentException("File must be in .md format.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Markdown to HTML using CommonMark
|
// Convert Markdown to HTML using CommonMark
|
||||||
Parser parser = Parser.builder().build();
|
List<Extension> extensions = List.of(TablesExtension.create());
|
||||||
|
Parser parser = Parser.builder().extensions(extensions).build();
|
||||||
|
|
||||||
Node document = parser.parse(new String(fileInput.getBytes()));
|
Node document = parser.parse(new String(fileInput.getBytes()));
|
||||||
HtmlRenderer renderer = HtmlRenderer.builder().build();
|
HtmlRenderer renderer =
|
||||||
|
HtmlRenderer.builder()
|
||||||
|
.attributeProviderFactory(context -> new TableAttributeProvider())
|
||||||
|
.extensions(extensions)
|
||||||
|
.build();
|
||||||
|
|
||||||
String htmlContent = renderer.render(document);
|
String htmlContent = renderer.render(document);
|
||||||
|
|
||||||
byte[] pdfBytes = FileToPdf.convertHtmlToPdf(htmlContent.getBytes(), "converted.html");
|
byte[] pdfBytes =
|
||||||
|
FileToPdf.convertHtmlToPdf(
|
||||||
|
null, htmlContent.getBytes(), "converted.html", htmlFormatsInstalled);
|
||||||
|
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
originalFilename.replaceFirst("[.][^.]+$", "")
|
originalFilename.replaceFirst("[.][^.]+$", "")
|
||||||
@ -54,3 +77,12 @@ public class ConvertMarkdownToPdf {
|
|||||||
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TableAttributeProvider implements AttributeProvider {
|
||||||
|
@Override
|
||||||
|
public void setAttributes(Node node, String tagName, Map<String, String> attributes) {
|
||||||
|
if (node instanceof TableBlock) {
|
||||||
|
attributes.put("class", "table table-striped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ public class ConvertOfficeController {
|
|||||||
|
|
||||||
public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
|
public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
|
||||||
// Check for valid file extension
|
// Check for valid file extension
|
||||||
String originalFilename = inputFile.getOriginalFilename();
|
String originalFilename = Filenames.toSimpleFileName(inputFile.getOriginalFilename());
|
||||||
if (originalFilename == null
|
if (originalFilename == null
|
||||||
|| !isValidFileExtension(FilenameUtils.getExtension(originalFilename))) {
|
|| !isValidFileExtension(FilenameUtils.getExtension(originalFilename))) {
|
||||||
throw new IllegalArgumentException("Invalid file extension");
|
throw new IllegalArgumentException("Invalid file extension");
|
||||||
@ -89,7 +90,8 @@ public class ConvertOfficeController {
|
|||||||
byte[] pdfByteArray = convertToPdf(inputFile);
|
byte[] pdfByteArray = convertToPdf(inputFile);
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
pdfByteArray,
|
pdfByteArray,
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_convertedToPDF.pdf");
|
+ "_convertedToPDF.pdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,103 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
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.github.pixee.security.Filenames;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.converters.PdfToBookRequest;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
@RequestMapping("/api/v1/convert")
|
||||||
|
public class ConvertPDFToBookController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("bookFormatsInstalled")
|
||||||
|
private boolean bookFormatsInstalled;
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/pdf/book")
|
||||||
|
@Operation(
|
||||||
|
summary =
|
||||||
|
"Convert a PDF to a Book/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx .. (others to include by chatgpt) to PDF",
|
||||||
|
description =
|
||||||
|
"(Requires bookFormatsInstalled flag and Calibre installed) This endpoint Convert a PDF to a Book/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx .. (others to include by chatgpt) to PDF")
|
||||||
|
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute PdfToBookRequest request)
|
||||||
|
throws Exception {
|
||||||
|
MultipartFile fileInput = request.getFileInput();
|
||||||
|
|
||||||
|
if (!bookFormatsInstalled) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"bookFormatsInstalled flag is False, this functionality is not avaiable");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileInput == null) {
|
||||||
|
throw new IllegalArgumentException("Please provide a file for conversion.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the output format
|
||||||
|
String outputFormat = request.getOutputFormat().toLowerCase();
|
||||||
|
List<String> allowedFormats =
|
||||||
|
Arrays.asList(
|
||||||
|
"epub", "mobi", "azw3", "docx", "rtf", "txt", "html", "lit", "fb2", "pdb",
|
||||||
|
"lrf");
|
||||||
|
if (!allowedFormats.contains(outputFormat)) {
|
||||||
|
throw new IllegalArgumentException("Invalid output format: " + outputFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] outputFileBytes;
|
||||||
|
List<String> command = new ArrayList<>();
|
||||||
|
Path tempOutputFile =
|
||||||
|
Files.createTempFile(
|
||||||
|
"output_",
|
||||||
|
"." + outputFormat); // Use the output format for the file extension
|
||||||
|
Path tempInputFile = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create temp input file from the provided PDF
|
||||||
|
tempInputFile = Files.createTempFile("input_", ".pdf"); // Assuming input is always PDF
|
||||||
|
Files.write(tempInputFile, fileInput.getBytes());
|
||||||
|
|
||||||
|
command.add("ebook-convert");
|
||||||
|
command.add(tempInputFile.toString());
|
||||||
|
command.add(tempOutputFile.toString());
|
||||||
|
|
||||||
|
ProcessExecutorResult returnCode =
|
||||||
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.CALIBRE)
|
||||||
|
.runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
|
outputFileBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
} finally {
|
||||||
|
// Clean up temporary files
|
||||||
|
if (tempInputFile != null) {
|
||||||
|
Files.deleteIfExists(tempInputFile);
|
||||||
|
}
|
||||||
|
Files.deleteIfExists(tempOutputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
String outputFilename =
|
||||||
|
Filenames.toSimpleFileName(fileInput.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "."
|
||||||
|
+ outputFormat; // Remove file extension and append .pdf
|
||||||
|
|
||||||
|
return WebResponseUtils.bytesToWebResponse(outputFileBytes, outputFilename);
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -63,7 +64,9 @@ public class ConvertPDFToPDFA {
|
|||||||
|
|
||||||
// Return the optimized PDF as a response
|
// Return the optimized PDF as a response
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_PDFA.pdf";
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_PDFA.pdf";
|
||||||
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import java.nio.file.Path;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
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;
|
||||||
@ -26,6 +28,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertWebsiteToPDF {
|
public class ConvertWebsiteToPDF {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("htmlFormatsInstalled")
|
||||||
|
private boolean htmlFormatsInstalled;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf")
|
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a URL to a PDF",
|
summary = "Convert a URL to a PDF",
|
||||||
@ -47,7 +53,11 @@ public class ConvertWebsiteToPDF {
|
|||||||
|
|
||||||
// Prepare the OCRmyPDF command
|
// Prepare the OCRmyPDF command
|
||||||
List<String> command = new ArrayList<>();
|
List<String> command = new ArrayList<>();
|
||||||
command.add("weasyprint");
|
if (!htmlFormatsInstalled) {
|
||||||
|
command.add("weasyprint");
|
||||||
|
} else {
|
||||||
|
command.add("wkhtmltopdf");
|
||||||
|
}
|
||||||
command.add(URL);
|
command.add(URL);
|
||||||
command.add(tempOutputFile.toString());
|
command.add(tempOutputFile.toString());
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package stirling.software.SPDF.controller.api.converters;
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -44,8 +44,7 @@ public class ExtractController {
|
|||||||
ArrayList<String> tableData = new ArrayList<>();
|
ArrayList<String> tableData = new ArrayList<>();
|
||||||
int columnsCount = 0;
|
int columnsCount = 0;
|
||||||
|
|
||||||
try (PDDocument document =
|
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) {
|
||||||
PDDocument.load(new ByteArrayInputStream(form.getFileInput().getBytes()))) {
|
|
||||||
final double res = 72; // PDF units are at 72 DPI
|
final double res = 72; // PDF units are at 72 DPI
|
||||||
PDFTableStripper stripper = new PDFTableStripper();
|
PDFTableStripper stripper = new PDFTableStripper();
|
||||||
PDPage pdPage = document.getPage(form.getPageId() - 1);
|
PDPage pdPage = document.getPage(form.getPageId() - 1);
|
||||||
|
@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.api.filters;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
@ -12,6 +13,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -39,10 +41,10 @@ public class FilterController {
|
|||||||
String text = request.getText();
|
String text = request.getText();
|
||||||
String pageNumber = request.getPageNumbers();
|
String pageNumber = request.getPageNumbers();
|
||||||
|
|
||||||
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
|
PDDocument pdfDocument = Loader.loadPDF(inputFile.getBytes());
|
||||||
if (PdfUtils.hasText(pdfDocument, pageNumber, text))
|
if (PdfUtils.hasText(pdfDocument, pageNumber, text))
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
pdfDocument, inputFile.getOriginalFilename());
|
pdfDocument, Filenames.toSimpleFileName(inputFile.getOriginalFilename()));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,10 +58,10 @@ public class FilterController {
|
|||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
String pageNumber = request.getPageNumbers();
|
String pageNumber = request.getPageNumbers();
|
||||||
|
|
||||||
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
|
PDDocument pdfDocument = Loader.loadPDF(inputFile.getBytes());
|
||||||
if (PdfUtils.hasImages(pdfDocument, pageNumber))
|
if (PdfUtils.hasImages(pdfDocument, pageNumber))
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
pdfDocument, inputFile.getOriginalFilename());
|
pdfDocument, Filenames.toSimpleFileName(inputFile.getOriginalFilename()));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +75,7 @@ public class FilterController {
|
|||||||
String pageCount = request.getPageCount();
|
String pageCount = request.getPageCount();
|
||||||
String comparator = request.getComparator();
|
String comparator = request.getComparator();
|
||||||
// Load the PDF
|
// Load the PDF
|
||||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
PDDocument document = Loader.loadPDF(inputFile.getBytes());
|
||||||
int actualPageCount = document.getNumberOfPages();
|
int actualPageCount = document.getNumberOfPages();
|
||||||
|
|
||||||
boolean valid = false;
|
boolean valid = false;
|
||||||
@ -107,7 +109,7 @@ public class FilterController {
|
|||||||
String comparator = request.getComparator();
|
String comparator = request.getComparator();
|
||||||
|
|
||||||
// Load the PDF
|
// Load the PDF
|
||||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
PDDocument document = Loader.loadPDF(inputFile.getBytes());
|
||||||
|
|
||||||
PDPage firstPage = document.getPage(0);
|
PDPage firstPage = document.getPage(0);
|
||||||
PDRectangle actualPageSize = firstPage.getMediaBox();
|
PDRectangle actualPageSize = firstPage.getMediaBox();
|
||||||
@ -183,7 +185,7 @@ public class FilterController {
|
|||||||
String comparator = request.getComparator();
|
String comparator = request.getComparator();
|
||||||
|
|
||||||
// Load the PDF
|
// Load the PDF
|
||||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
PDDocument document = Loader.loadPDF(inputFile.getBytes());
|
||||||
|
|
||||||
// Get the rotation of the first page
|
// Get the rotation of the first page
|
||||||
PDPage firstPage = document.getPage(0);
|
PDPage firstPage = document.getPage(0);
|
||||||
|
@ -5,6 +5,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.text.PDFTextStripper;
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
import org.apache.pdfbox.text.TextPosition;
|
import org.apache.pdfbox.text.TextPosition;
|
||||||
@ -17,6 +18,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -43,7 +45,7 @@ public class AutoRenameController {
|
|||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
Boolean useFirstTextAsFallback = request.isUseFirstTextAsFallback();
|
Boolean useFirstTextAsFallback = request.isUseFirstTextAsFallback();
|
||||||
|
|
||||||
PDDocument document = PDDocument.load(file.getInputStream());
|
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||||
PDFTextStripper reader =
|
PDFTextStripper reader =
|
||||||
new PDFTextStripper() {
|
new PDFTextStripper() {
|
||||||
class LineInfo {
|
class LineInfo {
|
||||||
@ -132,7 +134,8 @@ public class AutoRenameController {
|
|||||||
return WebResponseUtils.pdfDocToWebResponse(document, header + ".pdf");
|
return WebResponseUtils.pdfDocToWebResponse(document, header + ".pdf");
|
||||||
} else {
|
} else {
|
||||||
logger.info("File has no good title to be found");
|
logger.info("File has no good title to be found");
|
||||||
return WebResponseUtils.pdfDocToWebResponse(document, file.getOriginalFilename());
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
|
document, Filenames.toSimpleFileName(file.getOriginalFilename()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import java.awt.image.DataBufferByte;
|
|||||||
import java.awt.image.DataBufferInt;
|
import java.awt.image.DataBufferInt;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -13,6 +12,7 @@ import java.util.List;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -31,6 +31,7 @@ import com.google.zxing.PlanarYUVLuminanceSource;
|
|||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
import com.google.zxing.common.HybridBinarizer;
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
|
|
||||||
|
import io.github.pixee.security.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -43,6 +44,7 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
public class AutoSplitPdfController {
|
public class AutoSplitPdfController {
|
||||||
|
|
||||||
private static final String QR_CONTENT = "https://github.com/Stirling-Tools/Stirling-PDF";
|
private static final String QR_CONTENT = "https://github.com/Stirling-Tools/Stirling-PDF";
|
||||||
|
private static final String QR_CONTENT_OLD = "https://github.com/Frooodle/Stirling-PDF";
|
||||||
|
|
||||||
@PostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data")
|
@PostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data")
|
||||||
@Operation(
|
@Operation(
|
||||||
@ -54,8 +56,7 @@ public class AutoSplitPdfController {
|
|||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
boolean duplexMode = request.isDuplexMode();
|
boolean duplexMode = request.isDuplexMode();
|
||||||
|
|
||||||
InputStream inputStream = file.getInputStream();
|
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||||
PDDocument document = PDDocument.load(inputStream);
|
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
|
|
||||||
List<PDDocument> splitDocuments = new ArrayList<>();
|
List<PDDocument> splitDocuments = new ArrayList<>();
|
||||||
@ -64,12 +65,13 @@ public class AutoSplitPdfController {
|
|||||||
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
||||||
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150);
|
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150);
|
||||||
String result = decodeQRCode(bim);
|
String result = decodeQRCode(bim);
|
||||||
|
if ((QR_CONTENT.equals(result) || QR_CONTENT_OLD.equals(result)) && page != 0) {
|
||||||
if (QR_CONTENT.equals(result) && page != 0) {
|
|
||||||
splitDocuments.add(new PDDocument());
|
splitDocuments.add(new PDDocument());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!splitDocuments.isEmpty() && !QR_CONTENT.equals(result)) {
|
if (!splitDocuments.isEmpty()
|
||||||
|
&& !QR_CONTENT.equals(result)
|
||||||
|
&& !QR_CONTENT_OLD.equals(result)) {
|
||||||
splitDocuments.get(splitDocuments.size() - 1).addPage(document.getPage(page));
|
splitDocuments.get(splitDocuments.size() - 1).addPage(document.getPage(page));
|
||||||
} else if (page == 0) {
|
} else if (page == 0) {
|
||||||
PDDocument firstDocument = new PDDocument();
|
PDDocument firstDocument = new PDDocument();
|
||||||
@ -78,7 +80,7 @@ public class AutoSplitPdfController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If duplexMode is true and current page is a divider, then skip next page
|
// If duplexMode is true and current page is a divider, then skip next page
|
||||||
if (duplexMode && QR_CONTENT.equals(result)) {
|
if (duplexMode && (QR_CONTENT.equals(result) || QR_CONTENT_OLD.equals(result))) {
|
||||||
page++;
|
page++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,7 +98,9 @@ public class AutoSplitPdfController {
|
|||||||
document.close();
|
document.close();
|
||||||
|
|
||||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
||||||
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
|
String filename =
|
||||||
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "");
|
||||||
byte[] data;
|
byte[] data;
|
||||||
|
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
||||||
|
@ -13,6 +13,7 @@ import java.util.stream.IntStream;
|
|||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||||
@ -26,13 +27,13 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
|
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -53,7 +54,7 @@ public class BlankPageController {
|
|||||||
|
|
||||||
PDDocument document = null;
|
PDDocument document = null;
|
||||||
try {
|
try {
|
||||||
document = PDDocument.load(inputFile.getInputStream());
|
document = Loader.loadPDF(inputFile.getBytes());
|
||||||
PDPageTree pages = document.getDocumentCatalog().getPages();
|
PDPageTree pages = document.getDocumentCatalog().getPages();
|
||||||
PDFTextStripper textStripper = new PDFTextStripper();
|
PDFTextStripper textStripper = new PDFTextStripper();
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ public class BlankPageController {
|
|||||||
List<String> command =
|
List<String> command =
|
||||||
new ArrayList<>(
|
new ArrayList<>(
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
"python3",
|
"python",
|
||||||
System.getProperty("user.dir")
|
System.getProperty("user.dir")
|
||||||
+ "/scripts/detect-blank-pages.py",
|
+ "/scripts/detect-blank-pages.py",
|
||||||
tempFile.toString(),
|
tempFile.toString(),
|
||||||
@ -93,18 +94,25 @@ public class BlankPageController {
|
|||||||
"--white_percent",
|
"--white_percent",
|
||||||
String.valueOf(whitePercent)));
|
String.valueOf(whitePercent)));
|
||||||
|
|
||||||
|
Boolean blank = false;
|
||||||
// Run CLI command
|
// Run CLI command
|
||||||
ProcessExecutorResult returnCode =
|
try {
|
||||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
|
||||||
.runCommandWithOutputHandling(command);
|
.runCommandWithOutputHandling(command);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// From detect-blank-pages.py
|
||||||
|
// Return code 1: The image is considered blank.
|
||||||
|
// Return code 0: The image is not considered blank.
|
||||||
|
// Since the process returned with a failure code, it should be blank.
|
||||||
|
blank = true;
|
||||||
|
}
|
||||||
|
|
||||||
// does contain data
|
if (blank) {
|
||||||
if (returnCode.getRc() == 0) {
|
System.out.println("Skipping, Image was blank for page #" + pageIndex);
|
||||||
|
} else {
|
||||||
System.out.println(
|
System.out.println(
|
||||||
"page " + pageIndex + " has image which is not blank");
|
"page " + pageIndex + " has image which is not blank");
|
||||||
pagesToKeepIndex.add(pageIndex);
|
pagesToKeepIndex.add(pageIndex);
|
||||||
} else {
|
|
||||||
System.out.println("Skipping, Image was blank for page #" + pageIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,7 +132,8 @@ public class BlankPageController {
|
|||||||
|
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_blanksRemoved.pdf");
|
+ "_blanksRemoved.pdf");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -13,6 +13,7 @@ import java.util.List;
|
|||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
@ -28,6 +29,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -147,7 +149,7 @@ public class CompressController {
|
|||||||
if (expectedOutputSize != null && autoMode) {
|
if (expectedOutputSize != null && autoMode) {
|
||||||
long outputFileSize = Files.size(tempOutputFile);
|
long outputFileSize = Files.size(tempOutputFile);
|
||||||
if (outputFileSize > expectedOutputSize) {
|
if (outputFileSize > expectedOutputSize) {
|
||||||
try (PDDocument doc = PDDocument.load(new File(tempOutputFile.toString()))) {
|
try (PDDocument doc = Loader.loadPDF(new File(tempOutputFile.toString()))) {
|
||||||
long previousFileSize = 0;
|
long previousFileSize = 0;
|
||||||
double scaleFactor = 1.0;
|
double scaleFactor = 1.0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -263,7 +265,9 @@ public class CompressController {
|
|||||||
|
|
||||||
// Return the optimized PDF as a response
|
// Return the optimized PDF as a response
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_Optimized.pdf";
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_Optimized.pdf";
|
||||||
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package stirling.software.SPDF.controller.api.misc;
|
package stirling.software.SPDF.controller.api.misc;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -17,6 +16,7 @@ import java.util.zip.ZipOutputStream;
|
|||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -74,10 +74,9 @@ public class ExtractImageScansController {
|
|||||||
List<String> images = new ArrayList<>();
|
List<String> images = new ArrayList<>();
|
||||||
|
|
||||||
// Check if input file is a PDF
|
// Check if input file is a PDF
|
||||||
if (extension.equalsIgnoreCase("pdf")) {
|
if ("pdf".equalsIgnoreCase(extension)) {
|
||||||
// Load PDF document
|
// Load PDF document
|
||||||
try (PDDocument document =
|
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) {
|
||||||
PDDocument.load(new ByteArrayInputStream(form.getFileInput().getBytes()))) {
|
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
int pageCount = document.getNumberOfPages();
|
int pageCount = document.getNumberOfPages();
|
||||||
images = new ArrayList<>();
|
images = new ArrayList<>();
|
||||||
|
@ -14,6 +14,7 @@ import java.util.zip.ZipOutputStream;
|
|||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
@ -28,6 +29,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ public class ExtractImagesController {
|
|||||||
|
|
||||||
System.out.println(
|
System.out.println(
|
||||||
System.currentTimeMillis() + "file=" + file.getName() + ", format=" + format);
|
System.currentTimeMillis() + "file=" + file.getName() + ", format=" + format);
|
||||||
PDDocument document = PDDocument.load(file.getBytes());
|
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||||
|
|
||||||
// Create ByteArrayOutputStream to write zip file to byte array
|
// Create ByteArrayOutputStream to write zip file to byte array
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
@ -65,7 +67,9 @@ public class ExtractImagesController {
|
|||||||
zos.setLevel(Deflater.BEST_COMPRESSION);
|
zos.setLevel(Deflater.BEST_COMPRESSION);
|
||||||
|
|
||||||
int imageIndex = 1;
|
int imageIndex = 1;
|
||||||
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
|
String filename =
|
||||||
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "");
|
||||||
int pageNum = 0;
|
int pageNum = 0;
|
||||||
Set<Integer> processedImages = new HashSet<>();
|
Set<Integer> processedImages = new HashSet<>();
|
||||||
// Iterate over each page
|
// Iterate over each page
|
||||||
@ -84,19 +88,19 @@ public class ExtractImagesController {
|
|||||||
// Convert image to desired format
|
// Convert image to desired format
|
||||||
RenderedImage renderedImage = image.getImage();
|
RenderedImage renderedImage = image.getImage();
|
||||||
BufferedImage bufferedImage = null;
|
BufferedImage bufferedImage = null;
|
||||||
if (format.equalsIgnoreCase("png")) {
|
if ("png".equalsIgnoreCase(format)) {
|
||||||
bufferedImage =
|
bufferedImage =
|
||||||
new BufferedImage(
|
new BufferedImage(
|
||||||
renderedImage.getWidth(),
|
renderedImage.getWidth(),
|
||||||
renderedImage.getHeight(),
|
renderedImage.getHeight(),
|
||||||
BufferedImage.TYPE_INT_ARGB);
|
BufferedImage.TYPE_INT_ARGB);
|
||||||
} else if (format.equalsIgnoreCase("jpeg") || format.equalsIgnoreCase("jpg")) {
|
} else if ("jpeg".equalsIgnoreCase(format) || "jpg".equalsIgnoreCase(format)) {
|
||||||
bufferedImage =
|
bufferedImage =
|
||||||
new BufferedImage(
|
new BufferedImage(
|
||||||
renderedImage.getWidth(),
|
renderedImage.getWidth(),
|
||||||
renderedImage.getHeight(),
|
renderedImage.getHeight(),
|
||||||
BufferedImage.TYPE_INT_RGB);
|
BufferedImage.TYPE_INT_RGB);
|
||||||
} else if (format.equalsIgnoreCase("gif")) {
|
} else if ("gif".equalsIgnoreCase(format)) {
|
||||||
bufferedImage =
|
bufferedImage =
|
||||||
new BufferedImage(
|
new BufferedImage(
|
||||||
renderedImage.getWidth(),
|
renderedImage.getWidth(),
|
||||||
|
@ -16,6 +16,7 @@ import java.util.Random;
|
|||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
@ -28,11 +29,11 @@ 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.annotation.ModelAttribute;
|
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.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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Hidden;
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@ -49,7 +50,7 @@ public class FakeScanControllerWIP {
|
|||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@Hidden
|
@Hidden
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/fakeScan")
|
// @PostMapping(consumes = "multipart/form-data", value = "/fakeScan")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Repair a PDF file",
|
summary = "Repair a PDF file",
|
||||||
description =
|
description =
|
||||||
@ -57,7 +58,7 @@ public class FakeScanControllerWIP {
|
|||||||
public ResponseEntity<byte[]> repairPdf(@ModelAttribute PDFFile request) throws IOException {
|
public ResponseEntity<byte[]> repairPdf(@ModelAttribute PDFFile request) throws IOException {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
|
|
||||||
PDDocument document = PDDocument.load(inputFile.getBytes());
|
PDDocument document = Loader.loadPDF(inputFile.getBytes());
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
||||||
BufferedImage image = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
|
BufferedImage image = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
|
||||||
@ -141,7 +142,9 @@ public class FakeScanControllerWIP {
|
|||||||
|
|
||||||
// Return the optimized PDF as a response
|
// Return the optimized PDF as a response
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_scanned.pdf";
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_scanned.pdf";
|
||||||
return WebResponseUtils.boasToWebResponse(baos, outputFilename);
|
return WebResponseUtils.boasToWebResponse(baos, outputFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import java.util.Calendar;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
@ -17,6 +18,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ public class MetadataController {
|
|||||||
allRequestParams = new java.util.HashMap<String, String>();
|
allRequestParams = new java.util.HashMap<String, String>();
|
||||||
}
|
}
|
||||||
// Load the PDF file into a PDDocument
|
// Load the PDF file into a PDDocument
|
||||||
PDDocument document = PDDocument.load(pdfFile.getBytes());
|
PDDocument document = Loader.loadPDF(pdfFile.getBytes());
|
||||||
|
|
||||||
// Get the document information from the PDF
|
// Get the document information from the PDF
|
||||||
PDDocumentInformation info = document.getDocumentInformation();
|
PDDocumentInformation info = document.getDocumentInformation();
|
||||||
@ -108,15 +110,15 @@ public class MetadataController {
|
|||||||
for (Entry<String, String> entry : allRequestParams.entrySet()) {
|
for (Entry<String, String> entry : allRequestParams.entrySet()) {
|
||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
// Check if the key is a standard metadata key
|
// Check if the key is a standard metadata key
|
||||||
if (!key.equalsIgnoreCase("Author")
|
if (!"Author".equalsIgnoreCase(key)
|
||||||
&& !key.equalsIgnoreCase("CreationDate")
|
&& !"CreationDate".equalsIgnoreCase(key)
|
||||||
&& !key.equalsIgnoreCase("Creator")
|
&& !"Creator".equalsIgnoreCase(key)
|
||||||
&& !key.equalsIgnoreCase("Keywords")
|
&& !"Keywords".equalsIgnoreCase(key)
|
||||||
&& !key.equalsIgnoreCase("modificationDate")
|
&& !"modificationDate".equalsIgnoreCase(key)
|
||||||
&& !key.equalsIgnoreCase("Producer")
|
&& !"Producer".equalsIgnoreCase(key)
|
||||||
&& !key.equalsIgnoreCase("Subject")
|
&& !"Subject".equalsIgnoreCase(key)
|
||||||
&& !key.equalsIgnoreCase("Title")
|
&& !"Title".equalsIgnoreCase(key)
|
||||||
&& !key.equalsIgnoreCase("Trapped")
|
&& !"Trapped".equalsIgnoreCase(key)
|
||||||
&& !key.contains("customKey")
|
&& !key.contains("customKey")
|
||||||
&& !key.contains("customValue")) {
|
&& !key.contains("customValue")) {
|
||||||
info.setCustomMetadataValue(key, entry.getValue());
|
info.setCustomMetadataValue(key, entry.getValue());
|
||||||
@ -163,6 +165,8 @@ public class MetadataController {
|
|||||||
document.setDocumentInformation(info);
|
document.setDocumentInformation(info);
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_metadata.pdf");
|
Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_metadata.pdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ public class OCRController {
|
|||||||
throw new IOException("Please select at least one language.");
|
throw new IOException("Please select at least one language.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ocrRenderType.equals("hocr") && !ocrRenderType.equals("sandwich")) {
|
if (!"hocr".equals(ocrRenderType) && !"sandwich".equals(ocrRenderType)) {
|
||||||
throw new IOException("ocrRenderType wrong");
|
throw new IOException("ocrRenderType wrong");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +128,7 @@ public class OCRController {
|
|||||||
if (cleanFinal != null && cleanFinal) {
|
if (cleanFinal != null && cleanFinal) {
|
||||||
command.add("--clean-final");
|
command.add("--clean-final");
|
||||||
}
|
}
|
||||||
if (ocrType != null && !ocrType.equals("")) {
|
if (ocrType != null && !"".equals(ocrType)) {
|
||||||
if ("skip-text".equals(ocrType)) {
|
if ("skip-text".equals(ocrType)) {
|
||||||
command.add("--skip-text");
|
command.add("--skip-text");
|
||||||
} else if ("force-ocr".equals(ocrType)) {
|
} else if ("force-ocr".equals(ocrType)) {
|
||||||
@ -182,12 +183,16 @@ public class OCRController {
|
|||||||
|
|
||||||
// Return the OCR processed PDF as a response
|
// Return the OCR processed PDF as a response
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_OCR.pdf";
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_OCR.pdf";
|
||||||
|
|
||||||
if (sidecar != null && sidecar) {
|
if (sidecar != null && sidecar) {
|
||||||
// Create a zip file containing both the PDF and the text file
|
// Create a zip file containing both the PDF and the text file
|
||||||
String outputZipFilename =
|
String outputZipFilename =
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_OCR.zip";
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_OCR.zip";
|
||||||
Path tempZipFile = Files.createTempFile("output_", ".zip");
|
Path tempZipFile = Files.createTempFile("output_", ".zip");
|
||||||
|
|
||||||
try (ZipOutputStream zipOut =
|
try (ZipOutputStream zipOut =
|
||||||
|
@ -12,6 +12,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ public class OverlayImageController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Overlay image onto a PDF file",
|
summary = "Overlay image onto a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint overlays an image onto a PDF file at the specified coordinates. The image can be overlaid on every page of the PDF if specified. Input:PDF/IMAGE Output:PDF Type:MF-SISO")
|
"This endpoint overlays an image onto a PDF file at the specified coordinates. The image can be overlaid on every page of the PDF if specified. Input:PDF/IMAGE Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> overlayImage(@ModelAttribute OverlayImageRequest request) {
|
public ResponseEntity<byte[]> overlayImage(@ModelAttribute OverlayImageRequest request) {
|
||||||
MultipartFile pdfFile = request.getFileInput();
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
MultipartFile imageFile = request.getImageFile();
|
MultipartFile imageFile = request.getImageFile();
|
||||||
@ -44,7 +45,9 @@ public class OverlayImageController {
|
|||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
result,
|
result,
|
||||||
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_overlayed.pdf");
|
Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_overlayed.pdf");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("Failed to add image to PDF", e);
|
logger.error("Failed to add image to PDF", e);
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
@ -4,11 +4,13 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -19,6 +21,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -48,7 +51,7 @@ public class PageNumbersController {
|
|||||||
String customText = request.getCustomText();
|
String customText = request.getCustomText();
|
||||||
int pageNumber = startingNumber;
|
int pageNumber = startingNumber;
|
||||||
byte[] fileBytes = file.getBytes();
|
byte[] fileBytes = file.getBytes();
|
||||||
PDDocument document = PDDocument.load(fileBytes);
|
PDDocument document = Loader.loadPDF(fileBytes);
|
||||||
|
|
||||||
float marginFactor;
|
float marginFactor;
|
||||||
switch (customMargin.toLowerCase()) {
|
switch (customMargin.toLowerCase()) {
|
||||||
@ -71,7 +74,6 @@ public class PageNumbersController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float fontSize = 12.0f;
|
float fontSize = 12.0f;
|
||||||
PDType1Font font = PDType1Font.HELVETICA;
|
|
||||||
if (pagesToNumber == null || pagesToNumber.length() == 0) {
|
if (pagesToNumber == null || pagesToNumber.length() == 0) {
|
||||||
pagesToNumber = "all";
|
pagesToNumber = "all";
|
||||||
}
|
}
|
||||||
@ -92,7 +94,7 @@ public class PageNumbersController {
|
|||||||
.replace("{total}", String.valueOf(document.getNumberOfPages()))
|
.replace("{total}", String.valueOf(document.getNumberOfPages()))
|
||||||
.replace(
|
.replace(
|
||||||
"{filename}",
|
"{filename}",
|
||||||
file.getOriginalFilename()
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
.replaceFirst("[.][^.]+$", ""))
|
.replaceFirst("[.][^.]+$", ""))
|
||||||
: String.valueOf(pageNumber);
|
: String.valueOf(pageNumber);
|
||||||
|
|
||||||
@ -127,9 +129,9 @@ public class PageNumbersController {
|
|||||||
|
|
||||||
PDPageContentStream contentStream =
|
PDPageContentStream contentStream =
|
||||||
new PDPageContentStream(
|
new PDPageContentStream(
|
||||||
document, page, PDPageContentStream.AppendMode.APPEND, true);
|
document, page, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||||
contentStream.beginText();
|
contentStream.beginText();
|
||||||
contentStream.setFont(font, fontSize);
|
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), fontSize);
|
||||||
contentStream.newLineAtOffset(x, y);
|
contentStream.newLineAtOffset(x, y);
|
||||||
contentStream.showText(text);
|
contentStream.showText(text);
|
||||||
contentStream.endText();
|
contentStream.endText();
|
||||||
@ -144,7 +146,8 @@ public class PageNumbersController {
|
|||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
baos.toByteArray(),
|
baos.toByteArray(),
|
||||||
file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_numbersAdded.pdf",
|
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_numbersAdded.pdf",
|
||||||
MediaType.APPLICATION_PDF);
|
MediaType.APPLICATION_PDF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -65,7 +66,9 @@ public class RepairController {
|
|||||||
|
|
||||||
// Return the optimized PDF as a response
|
// Return the optimized PDF as a response
|
||||||
String outputFilename =
|
String outputFilename =
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_repaired.pdf";
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_repaired.pdf";
|
||||||
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package stirling.software.SPDF.controller.api.misc;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
|
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
|
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
|
||||||
@ -15,6 +16,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ public class ShowJavascript {
|
|||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
String script = "";
|
String script = "";
|
||||||
|
|
||||||
try (PDDocument document = PDDocument.load(inputFile.getInputStream())) {
|
try (PDDocument document = Loader.loadPDF(inputFile.getBytes())) {
|
||||||
|
|
||||||
if (document.getDocumentCatalog() != null
|
if (document.getDocumentCatalog() != null
|
||||||
&& document.getDocumentCatalog().getNames() != null) {
|
&& document.getDocumentCatalog().getNames() != null) {
|
||||||
@ -53,7 +55,8 @@ public class ShowJavascript {
|
|||||||
|
|
||||||
script +=
|
script +=
|
||||||
"// File: "
|
"// File: "
|
||||||
+ inputFile.getOriginalFilename()
|
+ Filenames.toSimpleFileName(
|
||||||
|
inputFile.getOriginalFilename())
|
||||||
+ ", Script: "
|
+ ", Script: "
|
||||||
+ name
|
+ name
|
||||||
+ "\n"
|
+ "\n"
|
||||||
@ -65,7 +68,7 @@ public class ShowJavascript {
|
|||||||
|
|
||||||
if (script.isEmpty()) {
|
if (script.isEmpty()) {
|
||||||
script =
|
script =
|
||||||
"PDF '" + inputFile.getOriginalFilename() + "' does not contain Javascript";
|
"PDF '" + Filenames.toSimpleFileName(inputFile.getOriginalFilename()) + "' does not contain Javascript";
|
||||||
}
|
}
|
||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
|
@ -0,0 +1,316 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.misc;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
||||||
|
import org.apache.pdfbox.util.Matrix;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
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.github.pixee.security.Filenames;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.misc.AddStampRequest;
|
||||||
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/misc")
|
||||||
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
|
public class StampController {
|
||||||
|
|
||||||
|
@PostMapping(consumes = "multipart/form-data", value = "/add-stamp")
|
||||||
|
@Operation(
|
||||||
|
summary = "Add stamp to a PDF file",
|
||||||
|
description =
|
||||||
|
"This endpoint adds a stamp to a given PDF file. Users can specify the watermark type (text or image), rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO")
|
||||||
|
public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request)
|
||||||
|
throws IOException, Exception {
|
||||||
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
|
String watermarkType = request.getStampType();
|
||||||
|
String watermarkText = request.getStampText();
|
||||||
|
MultipartFile watermarkImage = request.getStampImage();
|
||||||
|
String alphabet = request.getAlphabet();
|
||||||
|
float fontSize = request.getFontSize();
|
||||||
|
float rotation = request.getRotation();
|
||||||
|
float opacity = request.getOpacity();
|
||||||
|
int position = request.getPosition(); // Updated to use 1-9 positioning logic
|
||||||
|
float overrideX = request.getOverrideX(); // New field for X override
|
||||||
|
float overrideY = request.getOverrideY(); // New field for Y override
|
||||||
|
|
||||||
|
String customColor = request.getCustomColor();
|
||||||
|
float marginFactor;
|
||||||
|
|
||||||
|
switch (request.getCustomMargin().toLowerCase()) {
|
||||||
|
case "small":
|
||||||
|
marginFactor = 0.02f;
|
||||||
|
break;
|
||||||
|
case "medium":
|
||||||
|
marginFactor = 0.035f;
|
||||||
|
break;
|
||||||
|
case "large":
|
||||||
|
marginFactor = 0.05f;
|
||||||
|
break;
|
||||||
|
case "x-large":
|
||||||
|
marginFactor = 0.075f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
marginFactor = 0.035f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the input PDF
|
||||||
|
PDDocument document = Loader.loadPDF(pdfFile.getBytes());
|
||||||
|
|
||||||
|
for (PDPage page : document.getPages()) {
|
||||||
|
PDRectangle pageSize = page.getMediaBox();
|
||||||
|
float margin = marginFactor * (pageSize.getWidth() + pageSize.getHeight()) / 2;
|
||||||
|
|
||||||
|
PDPageContentStream contentStream =
|
||||||
|
new PDPageContentStream(
|
||||||
|
document, page, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||||
|
|
||||||
|
PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
|
||||||
|
graphicsState.setNonStrokingAlphaConstant(opacity);
|
||||||
|
contentStream.setGraphicsStateParameters(graphicsState);
|
||||||
|
|
||||||
|
if ("text".equalsIgnoreCase(watermarkType)) {
|
||||||
|
addTextStamp(
|
||||||
|
contentStream,
|
||||||
|
watermarkText,
|
||||||
|
document,
|
||||||
|
page,
|
||||||
|
rotation,
|
||||||
|
position,
|
||||||
|
fontSize,
|
||||||
|
alphabet,
|
||||||
|
overrideX,
|
||||||
|
overrideY,
|
||||||
|
margin,
|
||||||
|
customColor);
|
||||||
|
} else if ("image".equalsIgnoreCase(watermarkType)) {
|
||||||
|
addImageStamp(
|
||||||
|
contentStream,
|
||||||
|
watermarkImage,
|
||||||
|
document,
|
||||||
|
page,
|
||||||
|
rotation,
|
||||||
|
position,
|
||||||
|
fontSize,
|
||||||
|
overrideX,
|
||||||
|
overrideY,
|
||||||
|
margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
contentStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
|
document,
|
||||||
|
Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_watermarked.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTextStamp(
|
||||||
|
PDPageContentStream contentStream,
|
||||||
|
String watermarkText,
|
||||||
|
PDDocument document,
|
||||||
|
PDPage page,
|
||||||
|
float rotation,
|
||||||
|
int position, // 1-9 positioning logic
|
||||||
|
float fontSize,
|
||||||
|
String alphabet,
|
||||||
|
float overrideX, // X override
|
||||||
|
float overrideY,
|
||||||
|
float margin,
|
||||||
|
String colorString) // Y override
|
||||||
|
throws IOException {
|
||||||
|
String resourceDir = "";
|
||||||
|
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
||||||
|
switch (alphabet) {
|
||||||
|
case "arabic":
|
||||||
|
resourceDir = "static/fonts/NotoSansArabic-Regular.ttf";
|
||||||
|
break;
|
||||||
|
case "japanese":
|
||||||
|
resourceDir = "static/fonts/Meiryo.ttf";
|
||||||
|
break;
|
||||||
|
case "korean":
|
||||||
|
resourceDir = "static/fonts/malgun.ttf";
|
||||||
|
break;
|
||||||
|
case "chinese":
|
||||||
|
resourceDir = "static/fonts/SimSun.ttf";
|
||||||
|
break;
|
||||||
|
case "roman":
|
||||||
|
default:
|
||||||
|
resourceDir = "static/fonts/NotoSans-Regular.ttf";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!"".equals(resourceDir)) {
|
||||||
|
ClassPathResource classPathResource = new ClassPathResource(resourceDir);
|
||||||
|
String fileExtension = resourceDir.substring(resourceDir.lastIndexOf("."));
|
||||||
|
File tempFile = Files.createTempFile("NotoSansFont", fileExtension).toFile();
|
||||||
|
try (InputStream is = classPathResource.getInputStream();
|
||||||
|
FileOutputStream os = new FileOutputStream(tempFile)) {
|
||||||
|
IOUtils.copy(is, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
font = PDType0Font.load(document, tempFile);
|
||||||
|
tempFile.deleteOnExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
contentStream.setFont(font, fontSize);
|
||||||
|
|
||||||
|
Color redactColor;
|
||||||
|
try {
|
||||||
|
if (!colorString.startsWith("#")) {
|
||||||
|
colorString = "#" + colorString;
|
||||||
|
}
|
||||||
|
redactColor = Color.decode(colorString);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
|
||||||
|
redactColor = Color.LIGHT_GRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
contentStream.setNonStrokingColor(redactColor);
|
||||||
|
|
||||||
|
PDRectangle pageSize = page.getMediaBox();
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
if (overrideX >= 0 && overrideY >= 0) {
|
||||||
|
// Use override values if provided
|
||||||
|
x = overrideX;
|
||||||
|
y = overrideY;
|
||||||
|
} else {
|
||||||
|
x =
|
||||||
|
calculatePositionX(
|
||||||
|
pageSize, position, fontSize, font, fontSize, watermarkText, margin);
|
||||||
|
y =
|
||||||
|
calculatePositionY(
|
||||||
|
pageSize, position, calculateTextCapHeight(font, fontSize), margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
contentStream.beginText();
|
||||||
|
contentStream.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(rotation), x, y));
|
||||||
|
contentStream.showText(watermarkText);
|
||||||
|
contentStream.endText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addImageStamp(
|
||||||
|
PDPageContentStream contentStream,
|
||||||
|
MultipartFile watermarkImage,
|
||||||
|
PDDocument document,
|
||||||
|
PDPage page,
|
||||||
|
float rotation,
|
||||||
|
int position, // 1-9 positioning logic
|
||||||
|
float fontSize,
|
||||||
|
float overrideX,
|
||||||
|
float overrideY,
|
||||||
|
float margin)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
// Load the watermark image
|
||||||
|
BufferedImage image = ImageIO.read(watermarkImage.getInputStream());
|
||||||
|
|
||||||
|
// Compute width based on original aspect ratio
|
||||||
|
float aspectRatio = (float) image.getWidth() / (float) image.getHeight();
|
||||||
|
|
||||||
|
// Desired physical height (in PDF points)
|
||||||
|
float desiredPhysicalHeight = fontSize;
|
||||||
|
|
||||||
|
// Desired physical width based on the aspect ratio
|
||||||
|
float desiredPhysicalWidth = desiredPhysicalHeight * aspectRatio;
|
||||||
|
|
||||||
|
// Convert the BufferedImage to PDImageXObject
|
||||||
|
PDImageXObject xobject = LosslessFactory.createFromImage(document, image);
|
||||||
|
|
||||||
|
PDRectangle pageSize = page.getMediaBox();
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
if (overrideX >= 0 && overrideY >= 0) {
|
||||||
|
// Use override values if provided
|
||||||
|
x = overrideX;
|
||||||
|
y = overrideY;
|
||||||
|
} else {
|
||||||
|
x = calculatePositionX(pageSize, position, desiredPhysicalWidth, null, 0, null, margin);
|
||||||
|
y = calculatePositionY(pageSize, position, fontSize, margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
contentStream.saveGraphicsState();
|
||||||
|
contentStream.transform(Matrix.getTranslateInstance(x, y));
|
||||||
|
contentStream.transform(Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0));
|
||||||
|
contentStream.drawImage(xobject, 0, 0, desiredPhysicalWidth, desiredPhysicalHeight);
|
||||||
|
contentStream.restoreGraphicsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float calculatePositionX(
|
||||||
|
PDRectangle pageSize,
|
||||||
|
int position,
|
||||||
|
float contentWidth,
|
||||||
|
PDFont font,
|
||||||
|
float fontSize,
|
||||||
|
String text,
|
||||||
|
float margin)
|
||||||
|
throws IOException {
|
||||||
|
float actualWidth =
|
||||||
|
(text != null) ? calculateTextWidth(text, font, fontSize) : contentWidth;
|
||||||
|
switch (position % 3) {
|
||||||
|
case 1: // Left
|
||||||
|
return pageSize.getLowerLeftX() + margin;
|
||||||
|
case 2: // Center
|
||||||
|
return (pageSize.getWidth() - actualWidth) / 2;
|
||||||
|
case 0: // Right
|
||||||
|
return pageSize.getUpperRightX() - actualWidth - margin;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float calculatePositionY(
|
||||||
|
PDRectangle pageSize, int position, float height, float margin) {
|
||||||
|
switch ((position - 1) / 3) {
|
||||||
|
case 0: // Top
|
||||||
|
return pageSize.getUpperRightY() - height - margin;
|
||||||
|
case 1: // Middle
|
||||||
|
return (pageSize.getHeight() - height) / 2;
|
||||||
|
case 2: // Bottom
|
||||||
|
return pageSize.getLowerLeftY() + margin;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float calculateTextWidth(String text, PDFont font, float fontSize) throws IOException {
|
||||||
|
return font.getStringWidth(text) / 1000 * fontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float calculateTextCapHeight(PDFont font, float fontSize) {
|
||||||
|
return font.getFontDescriptor().getCapHeight() / 1000 * fontSize;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package stirling.software.SPDF.controller.api.pipeline;
|
package stirling.software.SPDF.controller.api.pipeline;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -39,6 +41,57 @@ public class ApiDocService {
|
|||||||
return "http://localhost:" + port + contextPath + "/v1/api-docs";
|
return "http://localhost:" + port + contextPath + "/v1/api-docs";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, List<String>> outputToFileTypes = new HashMap<>();
|
||||||
|
|
||||||
|
public List getExtensionTypes(boolean output, String operationName) {
|
||||||
|
if (outputToFileTypes.size() == 0) {
|
||||||
|
outputToFileTypes.put("PDF", Arrays.asList("pdf"));
|
||||||
|
outputToFileTypes.put(
|
||||||
|
"IMAGE",
|
||||||
|
Arrays.asList(
|
||||||
|
"png", "jpg", "jpeg", "gif", "webp", "bmp", "tif", "tiff", "svg", "psd",
|
||||||
|
"ai", "eps"));
|
||||||
|
outputToFileTypes.put(
|
||||||
|
"ZIP",
|
||||||
|
Arrays.asList("zip", "rar", "7z", "tar", "gz", "bz2", "xz", "lz", "lzma", "z"));
|
||||||
|
outputToFileTypes.put("WORD", Arrays.asList("doc", "docx", "odt", "rtf"));
|
||||||
|
outputToFileTypes.put("CSV", Arrays.asList("csv"));
|
||||||
|
outputToFileTypes.put("JS", Arrays.asList("js", "jsx"));
|
||||||
|
outputToFileTypes.put("HTML", Arrays.asList("html", "htm", "xhtml"));
|
||||||
|
outputToFileTypes.put("JSON", Arrays.asList("json"));
|
||||||
|
outputToFileTypes.put("TXT", Arrays.asList("txt", "text", "md", "markdown"));
|
||||||
|
outputToFileTypes.put("PPT", Arrays.asList("ppt", "pptx", "odp"));
|
||||||
|
outputToFileTypes.put("XML", Arrays.asList("xml", "xsd", "xsl"));
|
||||||
|
outputToFileTypes.put(
|
||||||
|
"BOOK", Arrays.asList("epub", "mobi", "azw3", "fb2", "txt", "docx"));
|
||||||
|
// type.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiDocsJsonRootNode == null || apiDocumentation.size() == 0) {
|
||||||
|
loadApiDocumentation();
|
||||||
|
}
|
||||||
|
if (!apiDocumentation.containsKey(operationName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiEndpoint endpoint = apiDocumentation.get(operationName);
|
||||||
|
String description = endpoint.getDescription();
|
||||||
|
Pattern pattern = null;
|
||||||
|
if (output) {
|
||||||
|
pattern = Pattern.compile("Output:(\\w+)");
|
||||||
|
} else {
|
||||||
|
pattern = Pattern.compile("Input:(\\w+)");
|
||||||
|
}
|
||||||
|
Matcher matcher = pattern.matcher(description);
|
||||||
|
while (matcher.find()) {
|
||||||
|
String type = matcher.group(1).toUpperCase();
|
||||||
|
if (outputToFileTypes.containsKey(type)) {
|
||||||
|
return outputToFileTypes.get(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private UserServiceInterface userService;
|
private UserServiceInterface userService;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@ -35,6 +36,9 @@ import org.springframework.util.MultiValueMap;
|
|||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.github.pixee.security.Filenames;
|
||||||
|
import io.github.pixee.security.ZipSecurity;
|
||||||
|
|
||||||
import jakarta.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import stirling.software.SPDF.SPdfApplication;
|
import stirling.software.SPDF.SPdfApplication;
|
||||||
import stirling.software.SPDF.model.PipelineConfig;
|
import stirling.software.SPDF.model.PipelineConfig;
|
||||||
@ -82,15 +86,11 @@ public class PipelineProcessor {
|
|||||||
operation,
|
operation,
|
||||||
isMultiInputOperation);
|
isMultiInputOperation);
|
||||||
Map<String, Object> parameters = pipelineOperation.getParameters();
|
Map<String, Object> parameters = pipelineOperation.getParameters();
|
||||||
String inputFileExtension = "";
|
List<String> inputFileTypes = apiDocService.getExtensionTypes(false, operation);
|
||||||
|
if (inputFileTypes == null) {
|
||||||
// TODO
|
inputFileTypes = new ArrayList<String>(Arrays.asList("ALL"));
|
||||||
// if (operationNode.has("inputFileType")) {
|
}
|
||||||
// inputFileExtension = operationNode.get("inputFileType").asText();
|
// List outputFileTypes = apiDocService.getExtensionTypes(true, operation);
|
||||||
// } else {
|
|
||||||
inputFileExtension = ".pdf";
|
|
||||||
// }
|
|
||||||
final String finalInputFileExtension = inputFileExtension;
|
|
||||||
|
|
||||||
String url = getBaseUrl() + operation;
|
String url = getBaseUrl() + operation;
|
||||||
|
|
||||||
@ -98,38 +98,42 @@ public class PipelineProcessor {
|
|||||||
if (!isMultiInputOperation) {
|
if (!isMultiInputOperation) {
|
||||||
for (Resource file : outputFiles) {
|
for (Resource file : outputFiles) {
|
||||||
boolean hasInputFileType = false;
|
boolean hasInputFileType = false;
|
||||||
if (file.getFilename().endsWith(inputFileExtension)) {
|
for (String extension : inputFileTypes) {
|
||||||
hasInputFileType = true;
|
if ("ALL".equals(extension) || file.getFilename().endsWith(extension)) {
|
||||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
hasInputFileType = true;
|
||||||
body.add("fileInput", file);
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("fileInput", file);
|
||||||
|
|
||||||
for (Entry<String, Object> entry : parameters.entrySet()) {
|
for (Entry<String, Object> entry : parameters.entrySet()) {
|
||||||
body.add(entry.getKey(), entry.getValue());
|
body.add(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseEntity<byte[]> response = sendWebRequest(url, body);
|
||||||
|
|
||||||
|
// If the operation is filter and the response body is null or empty,
|
||||||
|
// skip
|
||||||
|
// this
|
||||||
|
// file
|
||||||
|
if (operation.startsWith("filter-")
|
||||||
|
&& (response.getBody() == null
|
||||||
|
|| response.getBody().length == 0)) {
|
||||||
|
logger.info("Skipping file due to failing {}", operation);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
|
logPrintStream.println("Error: " + response.getBody());
|
||||||
|
hasErrors = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
processOutputFiles(operation, response, newOutputFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponseEntity<byte[]> response = sendWebRequest(url, body);
|
|
||||||
|
|
||||||
// If the operation is filter and the response body is null or empty, skip
|
|
||||||
// this
|
|
||||||
// file
|
|
||||||
if (operation.startsWith("filter-")
|
|
||||||
&& (response.getBody() == null || response.getBody().length == 0)) {
|
|
||||||
logger.info("Skipping file due to failing {}", operation);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.getStatusCode().equals(HttpStatus.OK)) {
|
|
||||||
logPrintStream.println("Error: " + response.getBody());
|
|
||||||
hasErrors = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
processOutputFiles(operation, file.getFilename(), response, newOutputFiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasInputFileType) {
|
if (!hasInputFileType) {
|
||||||
logPrintStream.println(
|
logPrintStream.println(
|
||||||
"No files with extension "
|
"No files with extension "
|
||||||
+ inputFileExtension
|
+ String.join(", ", inputFileTypes)
|
||||||
+ " found for operation "
|
+ " found for operation "
|
||||||
+ operation);
|
+ operation);
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
@ -138,13 +142,19 @@ public class PipelineProcessor {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Filter and collect all files that match the inputFileExtension
|
// Filter and collect all files that match the inputFileExtension
|
||||||
List<Resource> matchingFiles =
|
List<Resource> matchingFiles;
|
||||||
outputFiles.stream()
|
if (inputFileTypes.contains("ALL")) {
|
||||||
.filter(
|
matchingFiles = new ArrayList<>(outputFiles);
|
||||||
file ->
|
} else {
|
||||||
file.getFilename()
|
final List<String> finalinputFileTypes = inputFileTypes;
|
||||||
.endsWith(finalInputFileExtension))
|
matchingFiles =
|
||||||
.collect(Collectors.toList());
|
outputFiles.stream()
|
||||||
|
.filter(
|
||||||
|
file ->
|
||||||
|
finalinputFileTypes.stream()
|
||||||
|
.anyMatch(file.getFilename()::endsWith))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there are matching files
|
// Check if there are matching files
|
||||||
if (!matchingFiles.isEmpty()) {
|
if (!matchingFiles.isEmpty()) {
|
||||||
@ -164,11 +174,7 @@ public class PipelineProcessor {
|
|||||||
|
|
||||||
// Handle the response
|
// Handle the response
|
||||||
if (response.getStatusCode().equals(HttpStatus.OK)) {
|
if (response.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
processOutputFiles(
|
processOutputFiles(operation, response, newOutputFiles);
|
||||||
operation,
|
|
||||||
matchingFiles.get(0).getFilename(),
|
|
||||||
response,
|
|
||||||
newOutputFiles);
|
|
||||||
} else {
|
} else {
|
||||||
// Log error if the response status is not OK
|
// Log error if the response status is not OK
|
||||||
logPrintStream.println(
|
logPrintStream.println(
|
||||||
@ -178,7 +184,7 @@ public class PipelineProcessor {
|
|||||||
} else {
|
} else {
|
||||||
logPrintStream.println(
|
logPrintStream.println(
|
||||||
"No files with extension "
|
"No files with extension "
|
||||||
+ inputFileExtension
|
+ String.join(", ", inputFileTypes)
|
||||||
+ " found for multi-input operation "
|
+ " found for multi-input operation "
|
||||||
+ operation);
|
+ operation);
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
@ -211,11 +217,29 @@ public class PipelineProcessor {
|
|||||||
return restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
|
return restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String removeTrailingNaming(String filename) {
|
||||||
|
// Splitting filename into name and extension
|
||||||
|
int dotIndex = filename.lastIndexOf(".");
|
||||||
|
if (dotIndex == -1) {
|
||||||
|
// No extension found
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
String name = filename.substring(0, dotIndex);
|
||||||
|
String extension = filename.substring(dotIndex);
|
||||||
|
|
||||||
|
// Finding the last underscore
|
||||||
|
int underscoreIndex = name.lastIndexOf("_");
|
||||||
|
if (underscoreIndex == -1) {
|
||||||
|
// No underscore found
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removing the last part and reattaching the extension
|
||||||
|
return name.substring(0, underscoreIndex) + extension;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Resource> processOutputFiles(
|
private List<Resource> processOutputFiles(
|
||||||
String operation,
|
String operation, ResponseEntity<byte[]> response, List<Resource> newOutputFiles)
|
||||||
String fileName,
|
|
||||||
ResponseEntity<byte[]> response,
|
|
||||||
List<Resource> newOutputFiles)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// Define filename
|
// Define filename
|
||||||
String newFilename;
|
String newFilename;
|
||||||
@ -227,7 +251,7 @@ public class PipelineProcessor {
|
|||||||
newFilename = extractFilename(response);
|
newFilename = extractFilename(response);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, keep the original filename.
|
// Otherwise, keep the original filename.
|
||||||
newFilename = fileName;
|
newFilename = removeTrailingNaming(extractFilename(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the response body is a zip file
|
// Check if the response body is a zip file
|
||||||
@ -312,7 +336,7 @@ public class PipelineProcessor {
|
|||||||
new ByteArrayResource(file.getBytes()) {
|
new ByteArrayResource(file.getBytes()) {
|
||||||
@Override
|
@Override
|
||||||
public String getFilename() {
|
public String getFilename() {
|
||||||
return file.getOriginalFilename();
|
return Filenames.toSimpleFileName(file.getOriginalFilename());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
outputFiles.add(fileResource);
|
outputFiles.add(fileResource);
|
||||||
@ -335,7 +359,7 @@ public class PipelineProcessor {
|
|||||||
List<Resource> unzippedFiles = new ArrayList<>();
|
List<Resource> unzippedFiles = new ArrayList<>();
|
||||||
|
|
||||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||||
ZipInputStream zis = new ZipInputStream(bais)) {
|
ZipInputStream zis = ZipSecurity.createHardenedInputStream(bais)) {
|
||||||
|
|
||||||
ZipEntry entry;
|
ZipEntry entry;
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
while ((entry = zis.getNextEntry()) != null) {
|
||||||
|
@ -16,6 +16,7 @@ import java.security.cert.CertificateException;
|
|||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.examples.signature.CreateSignatureBase;
|
import org.apache.pdfbox.examples.signature.CreateSignatureBase;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
|
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
|
||||||
@ -41,6 +42,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -73,7 +75,7 @@ public class CertSignController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Sign PDF with a Digital Certificate",
|
summary = "Sign PDF with a Digital Certificate",
|
||||||
description =
|
description =
|
||||||
"This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:MF-SISO")
|
"This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request)
|
public ResponseEntity<byte[]> signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile pdf = request.getFileInput();
|
MultipartFile pdf = request.getFileInput();
|
||||||
@ -122,7 +124,9 @@ public class CertSignController {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
sign(pdf.getBytes(), baos, createSignature, name, location, reason);
|
sign(pdf.getBytes(), baos, createSignature, name, location, reason);
|
||||||
return WebResponseUtils.boasToWebResponse(
|
return WebResponseUtils.boasToWebResponse(
|
||||||
baos, pdf.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_signed.pdf");
|
baos,
|
||||||
|
Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_signed.pdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sign(
|
private static void sign(
|
||||||
@ -132,7 +136,7 @@ public class CertSignController {
|
|||||||
String name,
|
String name,
|
||||||
String location,
|
String location,
|
||||||
String reason) {
|
String reason) {
|
||||||
try (PDDocument doc = PDDocument.load(input)) {
|
try (PDDocument doc = Loader.loadPDF(input)) {
|
||||||
PDSignature signature = new PDSignature();
|
PDSignature signature = new PDSignature();
|
||||||
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
|
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
|
||||||
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
|
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
|
||||||
|
@ -11,11 +11,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.COSDocument;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.cos.COSInputStream;
|
import org.apache.pdfbox.cos.COSInputStream;
|
||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.cos.COSObject;
|
|
||||||
import org.apache.pdfbox.cos.COSStream;
|
|
||||||
import org.apache.pdfbox.cos.COSString;
|
import org.apache.pdfbox.cos.COSString;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||||
@ -87,7 +85,7 @@ public class GetInfoOnPDF {
|
|||||||
@Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO")
|
@Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO")
|
||||||
public ResponseEntity<byte[]> getPdfInfo(@ModelAttribute PDFFile request) throws IOException {
|
public ResponseEntity<byte[]> getPdfInfo(@ModelAttribute PDFFile request) throws IOException {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
try (PDDocument pdfBoxDoc = PDDocument.load(inputFile.getInputStream()); ) {
|
try (PDDocument pdfBoxDoc = Loader.loadPDF(inputFile.getBytes()); ) {
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
ObjectNode jsonOutput = objectMapper.createObjectNode();
|
ObjectNode jsonOutput = objectMapper.createObjectNode();
|
||||||
|
|
||||||
@ -129,17 +127,6 @@ public class GetInfoOnPDF {
|
|||||||
boolean hasCompression = false;
|
boolean hasCompression = false;
|
||||||
String compressionType = "None";
|
String compressionType = "None";
|
||||||
|
|
||||||
COSDocument cosDoc = pdfBoxDoc.getDocument();
|
|
||||||
for (COSObject cosObject : cosDoc.getObjects()) {
|
|
||||||
if (cosObject.getObject() instanceof COSStream) {
|
|
||||||
COSStream cosStream = (COSStream) cosObject.getObject();
|
|
||||||
if (COSName.OBJ_STM.equals(cosStream.getItem(COSName.TYPE))) {
|
|
||||||
hasCompression = true;
|
|
||||||
compressionType = "Object Streams";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
basicInfo.put("Compression", hasCompression);
|
basicInfo.put("Compression", hasCompression);
|
||||||
if (hasCompression) basicInfo.put("CompressionType", compressionType);
|
if (hasCompression) basicInfo.put("CompressionType", compressionType);
|
||||||
|
|
||||||
@ -343,7 +330,6 @@ public class GetInfoOnPDF {
|
|||||||
permissionsNode.put("CanModify", ap.canModify());
|
permissionsNode.put("CanModify", ap.canModify());
|
||||||
permissionsNode.put("CanModifyAnnotations", ap.canModifyAnnotations());
|
permissionsNode.put("CanModifyAnnotations", ap.canModifyAnnotations());
|
||||||
permissionsNode.put("CanPrint", ap.canPrint());
|
permissionsNode.put("CanPrint", ap.canPrint());
|
||||||
permissionsNode.put("CanPrintDegraded", ap.canPrintDegraded());
|
|
||||||
|
|
||||||
encryption.set(
|
encryption.set(
|
||||||
"Permissions", permissionsNode); // set the node under "Permissions"
|
"Permissions", permissionsNode); // set the node under "Permissions"
|
||||||
|
@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.api.security;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
|
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
|
||||||
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
|
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
|
||||||
@ -14,6 +15,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -38,11 +40,12 @@ public class PasswordController {
|
|||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
String password = request.getPassword();
|
String password = request.getPassword();
|
||||||
|
|
||||||
PDDocument document = PDDocument.load(fileInput.getBytes(), password);
|
PDDocument document = Loader.loadPDF(fileInput.getBytes(), password);
|
||||||
document.setAllSecurityToBeRemoved(true);
|
document.setAllSecurityToBeRemoved(true);
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
Filenames.toSimpleFileName(fileInput.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_password_removed.pdf");
|
+ "_password_removed.pdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +69,7 @@ public class PasswordController {
|
|||||||
boolean canPrint = request.isCanPrint();
|
boolean canPrint = request.isCanPrint();
|
||||||
boolean canPrintFaithful = request.isCanPrintFaithful();
|
boolean canPrintFaithful = request.isCanPrintFaithful();
|
||||||
|
|
||||||
PDDocument document = PDDocument.load(fileInput.getBytes());
|
PDDocument document = Loader.loadPDF(fileInput.getBytes());
|
||||||
AccessPermission ap = new AccessPermission();
|
AccessPermission ap = new AccessPermission();
|
||||||
ap.setCanAssembleDocument(!canAssembleDocument);
|
ap.setCanAssembleDocument(!canAssembleDocument);
|
||||||
ap.setCanExtractContent(!canExtractContent);
|
ap.setCanExtractContent(!canExtractContent);
|
||||||
@ -87,10 +90,13 @@ public class PasswordController {
|
|||||||
if ("".equals(ownerPassword) && "".equals(password))
|
if ("".equals(ownerPassword) && "".equals(password))
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
Filenames.toSimpleFileName(fileInput.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_permissions.pdf");
|
+ "_permissions.pdf");
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf");
|
Filenames.toSimpleFileName(fileInput.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_passworded.pdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,15 @@ package stirling.software.SPDF.controller.api.security;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||||
@ -24,6 +25,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -57,7 +59,7 @@ public class RedactController {
|
|||||||
System.out.println(listOfTextString);
|
System.out.println(listOfTextString);
|
||||||
String[] listOfText = listOfTextString.split("\n");
|
String[] listOfText = listOfTextString.split("\n");
|
||||||
byte[] bytes = file.getBytes();
|
byte[] bytes = file.getBytes();
|
||||||
PDDocument document = PDDocument.load(new ByteArrayInputStream(bytes));
|
PDDocument document = Loader.loadPDF(bytes);
|
||||||
|
|
||||||
Color redactColor;
|
Color redactColor;
|
||||||
try {
|
try {
|
||||||
@ -86,7 +88,9 @@ public class RedactController {
|
|||||||
PDPage newPage = new PDPage(new PDRectangle(bim.getWidth(), bim.getHeight()));
|
PDPage newPage = new PDPage(new PDRectangle(bim.getWidth(), bim.getHeight()));
|
||||||
imageDocument.addPage(newPage);
|
imageDocument.addPage(newPage);
|
||||||
PDImageXObject pdImage = LosslessFactory.createFromImage(imageDocument, bim);
|
PDImageXObject pdImage = LosslessFactory.createFromImage(imageDocument, bim);
|
||||||
PDPageContentStream contentStream = new PDPageContentStream(imageDocument, newPage);
|
PDPageContentStream contentStream =
|
||||||
|
new PDPageContentStream(
|
||||||
|
imageDocument, newPage, AppendMode.APPEND, true, true);
|
||||||
contentStream.drawImage(pdImage, 0, 0);
|
contentStream.drawImage(pdImage, 0, 0);
|
||||||
contentStream.close();
|
contentStream.close();
|
||||||
}
|
}
|
||||||
@ -101,7 +105,8 @@ public class RedactController {
|
|||||||
byte[] pdfContent = baos.toByteArray();
|
byte[] pdfContent = baos.toByteArray();
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
pdfContent,
|
pdfContent,
|
||||||
file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_redacted.pdf");
|
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_redacted.pdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void redactFoundText(
|
private void redactFoundText(
|
||||||
|
@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.api.security;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.cos.COSDictionary;
|
import org.apache.pdfbox.cos.COSDictionary;
|
||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
@ -27,6 +28,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -52,7 +54,7 @@ public class SanitizeController {
|
|||||||
boolean removeLinks = request.isRemoveLinks();
|
boolean removeLinks = request.isRemoveLinks();
|
||||||
boolean removeFonts = request.isRemoveFonts();
|
boolean removeFonts = request.isRemoveFonts();
|
||||||
|
|
||||||
try (PDDocument document = PDDocument.load(inputFile.getInputStream())) {
|
try (PDDocument document = Loader.loadPDF(inputFile.getBytes())) {
|
||||||
if (removeJavaScript) {
|
if (removeJavaScript) {
|
||||||
sanitizeJavaScript(document);
|
sanitizeJavaScript(document);
|
||||||
}
|
}
|
||||||
@ -75,7 +77,8 @@ public class SanitizeController {
|
|||||||
|
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_sanitized.pdf");
|
+ "_sanitized.pdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,19 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
||||||
@ -28,6 +31,7 @@ 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.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
@ -58,7 +62,7 @@ public class WatermarkController {
|
|||||||
int heightSpacer = request.getHeightSpacer();
|
int heightSpacer = request.getHeightSpacer();
|
||||||
|
|
||||||
// Load the input PDF
|
// Load the input PDF
|
||||||
PDDocument document = PDDocument.load(pdfFile.getInputStream());
|
PDDocument document = Loader.loadPDF(pdfFile.getBytes());
|
||||||
|
|
||||||
// Create a page in the document
|
// Create a page in the document
|
||||||
for (PDPage page : document.getPages()) {
|
for (PDPage page : document.getPages()) {
|
||||||
@ -66,14 +70,14 @@ public class WatermarkController {
|
|||||||
// Get the page's content stream
|
// Get the page's content stream
|
||||||
PDPageContentStream contentStream =
|
PDPageContentStream contentStream =
|
||||||
new PDPageContentStream(
|
new PDPageContentStream(
|
||||||
document, page, PDPageContentStream.AppendMode.APPEND, true);
|
document, page, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||||
|
|
||||||
// Set transparency
|
// Set transparency
|
||||||
PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
|
PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
|
||||||
graphicsState.setNonStrokingAlphaConstant(opacity);
|
graphicsState.setNonStrokingAlphaConstant(opacity);
|
||||||
contentStream.setGraphicsStateParameters(graphicsState);
|
contentStream.setGraphicsStateParameters(graphicsState);
|
||||||
|
|
||||||
if (watermarkType.equalsIgnoreCase("text")) {
|
if ("text".equalsIgnoreCase(watermarkType)) {
|
||||||
addTextWatermark(
|
addTextWatermark(
|
||||||
contentStream,
|
contentStream,
|
||||||
watermarkText,
|
watermarkText,
|
||||||
@ -84,7 +88,7 @@ public class WatermarkController {
|
|||||||
heightSpacer,
|
heightSpacer,
|
||||||
fontSize,
|
fontSize,
|
||||||
alphabet);
|
alphabet);
|
||||||
} else if (watermarkType.equalsIgnoreCase("image")) {
|
} else if ("image".equalsIgnoreCase(watermarkType)) {
|
||||||
addImageWatermark(
|
addImageWatermark(
|
||||||
contentStream,
|
contentStream,
|
||||||
watermarkImage,
|
watermarkImage,
|
||||||
@ -102,7 +106,9 @@ public class WatermarkController {
|
|||||||
|
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
document,
|
document,
|
||||||
pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
|
Filenames.toSimpleFileName(pdfFile.getOriginalFilename())
|
||||||
|
.replaceFirst("[.][^.]+$", "")
|
||||||
|
+ "_watermarked.pdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addTextWatermark(
|
private void addTextWatermark(
|
||||||
@ -117,7 +123,7 @@ public class WatermarkController {
|
|||||||
String alphabet)
|
String alphabet)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String resourceDir = "";
|
String resourceDir = "";
|
||||||
PDFont font = PDType1Font.HELVETICA_BOLD;
|
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
||||||
switch (alphabet) {
|
switch (alphabet) {
|
||||||
case "arabic":
|
case "arabic":
|
||||||
resourceDir = "static/fonts/NotoSansArabic-Regular.ttf";
|
resourceDir = "static/fonts/NotoSansArabic-Regular.ttf";
|
||||||
@ -137,10 +143,10 @@ public class WatermarkController {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resourceDir.equals("")) {
|
if (!"".equals(resourceDir)) {
|
||||||
ClassPathResource classPathResource = new ClassPathResource(resourceDir);
|
ClassPathResource classPathResource = new ClassPathResource(resourceDir);
|
||||||
String fileExtension = resourceDir.substring(resourceDir.lastIndexOf("."));
|
String fileExtension = resourceDir.substring(resourceDir.lastIndexOf("."));
|
||||||
File tempFile = File.createTempFile("NotoSansFont", fileExtension);
|
File tempFile = Files.createTempFile("NotoSansFont", fileExtension).toFile();
|
||||||
try (InputStream is = classPathResource.getInputStream();
|
try (InputStream is = classPathResource.getInputStream();
|
||||||
FileOutputStream os = new FileOutputStream(tempFile)) {
|
FileOutputStream os = new FileOutputStream(tempFile)) {
|
||||||
IOUtils.copy(is, os);
|
IOUtils.copy(is, os);
|
||||||
@ -153,9 +159,16 @@ public class WatermarkController {
|
|||||||
contentStream.setFont(font, fontSize);
|
contentStream.setFont(font, fontSize);
|
||||||
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
|
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
|
||||||
|
|
||||||
|
String[] textLines = watermarkText.split("\\\\n");
|
||||||
|
float maxLineWidth = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < textLines.length; ++i) {
|
||||||
|
maxLineWidth = Math.max(maxLineWidth, font.getStringWidth(textLines[i]));
|
||||||
|
}
|
||||||
|
|
||||||
// Set size and location of text watermark
|
// Set size and location of text watermark
|
||||||
float watermarkWidth = widthSpacer + font.getStringWidth(watermarkText) * fontSize / 1000;
|
float watermarkWidth = widthSpacer + maxLineWidth * fontSize / 1000;
|
||||||
float watermarkHeight = heightSpacer + fontSize;
|
float watermarkHeight = heightSpacer + fontSize * textLines.length;
|
||||||
float pageWidth = page.getMediaBox().getWidth();
|
float pageWidth = page.getMediaBox().getWidth();
|
||||||
float pageHeight = page.getMediaBox().getHeight();
|
float pageHeight = page.getMediaBox().getHeight();
|
||||||
int watermarkRows = (int) (pageHeight / watermarkHeight + 1);
|
int watermarkRows = (int) (pageHeight / watermarkHeight + 1);
|
||||||
@ -170,7 +183,12 @@ public class WatermarkController {
|
|||||||
(float) Math.toRadians(rotation),
|
(float) Math.toRadians(rotation),
|
||||||
j * watermarkWidth,
|
j * watermarkWidth,
|
||||||
i * watermarkHeight));
|
i * watermarkHeight));
|
||||||
contentStream.showText(watermarkText);
|
|
||||||
|
for (int k = 0; k < textLines.length; ++k) {
|
||||||
|
contentStream.showText(textLines[k]);
|
||||||
|
contentStream.newLineAtOffset(0, -fontSize);
|
||||||
|
}
|
||||||
|
|
||||||
contentStream.endText();
|
contentStream.endText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.controller.web;
|
package stirling.software.SPDF.controller.web;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -12,6 +13,22 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
public class ConverterWebController {
|
public class ConverterWebController {
|
||||||
|
|
||||||
|
@ConditionalOnExpression("#{bookFormatsInstalled}")
|
||||||
|
@GetMapping("/book-to-pdf")
|
||||||
|
@Hidden
|
||||||
|
public String convertBookToPdfForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "book-to-pdf");
|
||||||
|
return "convert/book-to-pdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnExpression("#{bookFormatsInstalled}")
|
||||||
|
@GetMapping("/pdf-to-book")
|
||||||
|
@Hidden
|
||||||
|
public String convertPdfToBookForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "pdf-to-book");
|
||||||
|
return "convert/pdf-to-book";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/img-to-pdf")
|
@GetMapping("/img-to-pdf")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String convertImgToPdfForm(Model model) {
|
public String convertImgToPdfForm(Model model) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package stirling.software.SPDF.controller.web;
|
package stirling.software.SPDF.controller.web;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -38,7 +39,8 @@ public class HomeWebController {
|
|||||||
model.addAttribute("currentPage", "licenses");
|
model.addAttribute("currentPage", "licenses");
|
||||||
Resource resource = new ClassPathResource("static/3rdPartyLicenses.json");
|
Resource resource = new ClassPathResource("static/3rdPartyLicenses.json");
|
||||||
try {
|
try {
|
||||||
String json = new String(Files.readAllBytes(resource.getFile().toPath()));
|
InputStream is = resource.getInputStream();
|
||||||
|
String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
Map<String, List<Dependency>> data =
|
Map<String, List<Dependency>> data =
|
||||||
mapper.readValue(json, new TypeReference<Map<String, List<Dependency>>>() {});
|
mapper.readValue(json, new TypeReference<Map<String, List<Dependency>>>() {});
|
||||||
|
@ -84,7 +84,7 @@ public class MetricsController {
|
|||||||
for (Meter meter : meterRegistry.getMeters()) {
|
for (Meter meter : meterRegistry.getMeters()) {
|
||||||
if (meter.getId().getName().equals("http.requests")) {
|
if (meter.getId().getName().equals("http.requests")) {
|
||||||
String method = meter.getId().getTag("method");
|
String method = meter.getId().getTag("method");
|
||||||
if (method != null && method.equals("GET")) {
|
if (method != null && "GET".equals(method)) {
|
||||||
|
|
||||||
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
|
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
|
||||||
if (!endpoint.get().startsWith("/")) {
|
if (!endpoint.get().startsWith("/")) {
|
||||||
@ -129,7 +129,7 @@ public class MetricsController {
|
|||||||
for (Meter meter : meterRegistry.getMeters()) {
|
for (Meter meter : meterRegistry.getMeters()) {
|
||||||
if (meter.getId().getName().equals("http.requests")) {
|
if (meter.getId().getName().equals("http.requests")) {
|
||||||
String method = meter.getId().getTag("method");
|
String method = meter.getId().getTag("method");
|
||||||
if (method != null && method.equals("GET")) {
|
if (method != null && "GET".equals(method)) {
|
||||||
String uri = meter.getId().getTag("uri");
|
String uri = meter.getId().getTag("uri");
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
double currentCount = counts.getOrDefault(uri, 0.0);
|
double currentCount = counts.getOrDefault(uri, 0.0);
|
||||||
@ -197,7 +197,7 @@ public class MetricsController {
|
|||||||
for (Meter meter : meterRegistry.getMeters()) {
|
for (Meter meter : meterRegistry.getMeters()) {
|
||||||
if (meter.getId().getName().equals("http.requests")) {
|
if (meter.getId().getName().equals("http.requests")) {
|
||||||
String method = meter.getId().getTag("method");
|
String method = meter.getId().getTag("method");
|
||||||
if (method != null && method.equals("POST")) {
|
if (method != null && "POST".equals(method)) {
|
||||||
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
|
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
|
||||||
if (!endpoint.get().startsWith("/")) {
|
if (!endpoint.get().startsWith("/")) {
|
||||||
endpoint = Optional.of("/" + endpoint.get());
|
endpoint = Optional.of("/" + endpoint.get());
|
||||||
@ -235,7 +235,7 @@ public class MetricsController {
|
|||||||
for (Meter meter : meterRegistry.getMeters()) {
|
for (Meter meter : meterRegistry.getMeters()) {
|
||||||
if (meter.getId().getName().equals("http.requests")) {
|
if (meter.getId().getName().equals("http.requests")) {
|
||||||
String method = meter.getId().getTag("method");
|
String method = meter.getId().getTag("method");
|
||||||
if (method != null && method.equals("POST")) {
|
if (method != null && "POST".equals(method)) {
|
||||||
String uri = meter.getId().getTag("uri");
|
String uri = meter.getId().getTag("uri");
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
double currentCount = counts.getOrDefault(uri, 0.0);
|
double currentCount = counts.getOrDefault(uri, 0.0);
|
||||||
|
@ -39,6 +39,13 @@ public class OtherWebController {
|
|||||||
return "misc/show-javascript";
|
return "misc/show-javascript";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/stamp")
|
||||||
|
@Hidden
|
||||||
|
public String stampForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "stamp");
|
||||||
|
return "misc/stamp";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/add-page-numbers")
|
@GetMapping("/add-page-numbers")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String addPageNumbersForm(Model model) {
|
public String addPageNumbersForm(Model model) {
|
||||||
|
@ -210,6 +210,7 @@ public class ApplicationProperties {
|
|||||||
private String rootURIPath;
|
private String rootURIPath;
|
||||||
private String customStaticFilePath;
|
private String customStaticFilePath;
|
||||||
private Integer maxFileSize;
|
private Integer maxFileSize;
|
||||||
|
private CustomApplications customApplications;
|
||||||
|
|
||||||
private Boolean enableAlphaFunctionality;
|
private Boolean enableAlphaFunctionality;
|
||||||
|
|
||||||
@ -261,6 +262,14 @@ public class ApplicationProperties {
|
|||||||
this.maxFileSize = maxFileSize;
|
this.maxFileSize = maxFileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CustomApplications getCustomApplications() {
|
||||||
|
return customApplications != null ? customApplications : new CustomApplications();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomApplications(CustomApplications customApplications) {
|
||||||
|
this.customApplications = customApplications;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "System [defaultLocale="
|
return "System [defaultLocale="
|
||||||
@ -273,10 +282,42 @@ public class ApplicationProperties {
|
|||||||
+ customStaticFilePath
|
+ customStaticFilePath
|
||||||
+ ", maxFileSize="
|
+ ", maxFileSize="
|
||||||
+ maxFileSize
|
+ maxFileSize
|
||||||
|
+ ", customApplications="
|
||||||
|
+ customApplications
|
||||||
+ ", enableAlphaFunctionality="
|
+ ", enableAlphaFunctionality="
|
||||||
+ enableAlphaFunctionality
|
+ enableAlphaFunctionality
|
||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class CustomApplications {
|
||||||
|
private boolean installBookFormats;
|
||||||
|
private boolean installAdvancedHtmlToPDF;
|
||||||
|
|
||||||
|
public boolean isInstallBookFormats() {
|
||||||
|
return installBookFormats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstallBookFormats(boolean installBookFormats) {
|
||||||
|
this.installBookFormats = installBookFormats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInstallAdvancedHtmlToPDF() {
|
||||||
|
return installAdvancedHtmlToPDF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstallAdvancedHtmlToPDF(boolean installAdvancedHtmlToPDF) {
|
||||||
|
this.installAdvancedHtmlToPDF = installAdvancedHtmlToPDF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CustomApplications [installBookFormats="
|
||||||
|
+ installBookFormats
|
||||||
|
+ ", installAdvancedHtmlToPDF="
|
||||||
|
+ installAdvancedHtmlToPDF
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Ui {
|
public static class Ui {
|
||||||
|
@ -3,6 +3,7 @@ package stirling.software.SPDF.model.api;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Hidden;
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
@ -27,7 +28,7 @@ public class PDFWithPageNums extends PDFFile {
|
|||||||
public List<Integer> getPageNumbersList() {
|
public List<Integer> getPageNumbersList() {
|
||||||
int pageCount = 0;
|
int pageCount = 0;
|
||||||
try {
|
try {
|
||||||
pageCount = PDDocument.load(getFileInput().getInputStream()).getNumberOfPages();
|
pageCount = Loader.loadPDF(getFileInput().getBytes()).getNumberOfPages();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package stirling.software.SPDF.model.api.converters;
|
||||||
|
|
||||||
|
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 HTMLToPdfRequest extends PDFFile {
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "Zoom level for displaying the website. Default is '1'.",
|
||||||
|
defaultValue = "1")
|
||||||
|
private float zoom;
|
||||||
|
|
||||||
|
@Schema(description = "Width of the page in centimeters.")
|
||||||
|
private Float pageWidth;
|
||||||
|
|
||||||
|
@Schema(description = "Height of the page in centimeters.")
|
||||||
|
private Float pageHeight;
|
||||||
|
|
||||||
|
@Schema(description = "Top margin of the page in millimeters.")
|
||||||
|
private Float marginTop;
|
||||||
|
|
||||||
|
@Schema(description = "Bottom margin of the page in millimeters.")
|
||||||
|
private Float marginBottom;
|
||||||
|
|
||||||
|
@Schema(description = "Left margin of the page in millimeters.")
|
||||||
|
private Float marginLeft;
|
||||||
|
|
||||||
|
@Schema(description = "Right margin of the page in millimeters.")
|
||||||
|
private Float marginRight;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "Enable or disable rendering of website background.",
|
||||||
|
allowableValues = {"Yes", "No"})
|
||||||
|
private String printBackground;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description =
|
||||||
|
"Enable or disable the default header. The default header includes the name of the page on the left and the page number on the right.",
|
||||||
|
allowableValues = {"Yes", "No"})
|
||||||
|
private String defaultHeader;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "Change the CSS media type of the page. Defaults to 'print'.",
|
||||||
|
allowableValues = {"none", "print", "screen"},
|
||||||
|
defaultValue = "print")
|
||||||
|
private String cssMediaType;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package stirling.software.SPDF.model.api.converters;
|
||||||
|
|
||||||
|
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 PdfToBookRequest extends PDFFile {
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "The output Ebook format",
|
||||||
|
allowableValues = {
|
||||||
|
"epub", "mobi", "azw3", "docx", "rtf", "txt", "html", "lit", "fb2", "pdb", "lrf"
|
||||||
|
})
|
||||||
|
private String outputFormat;
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package stirling.software.SPDF.model.api.misc;
|
||||||
|
|
||||||
|
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 AddStampRequest extends PDFFile {
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "The stamp type (text or image)",
|
||||||
|
allowableValues = {"text", "image"},
|
||||||
|
required = true)
|
||||||
|
private String stampType;
|
||||||
|
|
||||||
|
@Schema(description = "The stamp text")
|
||||||
|
private String stampText;
|
||||||
|
|
||||||
|
@Schema(description = "The stamp image")
|
||||||
|
private MultipartFile stampImage;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "The selected alphabet",
|
||||||
|
allowableValues = {"roman", "arabic", "japanese", "korean", "chinese"},
|
||||||
|
defaultValue = "roman")
|
||||||
|
private String alphabet = "roman";
|
||||||
|
|
||||||
|
@Schema(description = "The font size of the stamp text", example = "30")
|
||||||
|
private float fontSize = 30;
|
||||||
|
|
||||||
|
@Schema(description = "The rotation of the stamp in degrees", example = "0")
|
||||||
|
private float rotation = 0;
|
||||||
|
|
||||||
|
@Schema(description = "The opacity of the stamp (0.0 - 1.0)", example = "0.5")
|
||||||
|
private float opacity;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description =
|
||||||
|
"Position for stamp placement based on a 1-9 grid (1: bottom-left, 2: bottom-center, ..., 9: top-right)",
|
||||||
|
example = "1")
|
||||||
|
private int position;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description =
|
||||||
|
"Override X coordinate for stamp placement. If set, it will override the position-based calculation. Negative value means no override.",
|
||||||
|
example = "-1")
|
||||||
|
private float overrideX = -1; // Default to -1 indicating no override
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description =
|
||||||
|
"Override Y coordinate for stamp placement. If set, it will override the position-based calculation. Negative value means no override.",
|
||||||
|
example = "-1")
|
||||||
|
private float overrideY = -1; // Default to -1 indicating no override
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "Specifies the margin size for the stamp.",
|
||||||
|
allowableValues = {"small", "medium", "large", "x-large"},
|
||||||
|
defaultValue = "medium")
|
||||||
|
private String customMargin = "medium";
|
||||||
|
|
||||||
|
@Schema(description = "The color for stamp", defaultValue = "#d3d3d3")
|
||||||
|
private String customColor = "#d3d3d3";
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package stirling.software.SPDF.model.api.user;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class UpdateUserDetails extends UpdateUserUsername {
|
||||||
|
|
||||||
|
@Schema(description = "new password for user")
|
||||||
|
private String newPassword;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package stirling.software.SPDF.model.api.user;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class UpdateUserUsername extends UsernameAndPass {
|
||||||
|
|
||||||
|
@Schema(description = "new password for user")
|
||||||
|
private String newUsername;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package stirling.software.SPDF.model.api.user;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Username {
|
||||||
|
|
||||||
|
@Schema(description = "username of user")
|
||||||
|
private String username;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package stirling.software.SPDF.model.api.user;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class UsernameAndPass extends Username {
|
||||||
|
|
||||||
|
@Schema(description = "password of user")
|
||||||
|
private String password;
|
||||||
|
}
|
@ -1,131 +0,0 @@
|
|||||||
package stirling.software.SPDF.pdf;
|
|
||||||
|
|
||||||
import java.awt.geom.Point2D;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.contentstream.operator.Operator;
|
|
||||||
import org.apache.pdfbox.contentstream.operator.OperatorName;
|
|
||||||
import org.apache.pdfbox.cos.COSBase;
|
|
||||||
import org.apache.pdfbox.cos.COSName;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImage;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|
||||||
|
|
||||||
public class ImageFinder extends org.apache.pdfbox.contentstream.PDFGraphicsStreamEngine {
|
|
||||||
private boolean hasImages = false;
|
|
||||||
|
|
||||||
public ImageFinder(PDPage page) {
|
|
||||||
super(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasImages() {
|
|
||||||
return hasImages;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
|
|
||||||
String operation = operator.getName();
|
|
||||||
if (operation.equals(OperatorName.DRAW_OBJECT)) {
|
|
||||||
COSBase base = operands.get(0);
|
|
||||||
if (base instanceof COSName) {
|
|
||||||
COSName objectName = (COSName) base;
|
|
||||||
PDXObject xobject = getResources().getXObject(objectName);
|
|
||||||
if (xobject instanceof PDImageXObject) {
|
|
||||||
hasImages = true;
|
|
||||||
} else if (xobject instanceof PDFormXObject) {
|
|
||||||
PDFormXObject form = (PDFormXObject) xobject;
|
|
||||||
ImageFinder innerFinder = new ImageFinder(getPage());
|
|
||||||
innerFinder.processPage(getPage());
|
|
||||||
if (innerFinder.hasImages()) {
|
|
||||||
hasImages = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.processOperator(operator, operands);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawImage(PDImage pdImage) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clip(int windingRule) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void moveTo(float x, float y) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void lineTo(float x, float y) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3)
|
|
||||||
throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Point2D getCurrentPoint() throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void closePath() throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void endPath() throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void strokePath() throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fillPath(int windingRule) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fillAndStrokePath(int windingRule) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shadingFill(COSName shadingName) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... rest of the overridden methods
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ package stirling.software.SPDF.utils;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -11,10 +12,18 @@ import java.util.stream.Stream;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import io.github.pixee.security.ZipSecurity;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
|
||||||
public class FileToPdf {
|
public class FileToPdf {
|
||||||
public static byte[] convertHtmlToPdf(byte[] fileBytes, String fileName)
|
|
||||||
|
public static byte[] convertHtmlToPdf(
|
||||||
|
HTMLToPdfRequest request,
|
||||||
|
byte[] fileBytes,
|
||||||
|
String fileName,
|
||||||
|
boolean htmlFormatsInstalled)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
|
|
||||||
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||||
@ -29,11 +38,81 @@ public class FileToPdf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<String> command = new ArrayList<>();
|
List<String> command = new ArrayList<>();
|
||||||
command.add("weasyprint");
|
if (!htmlFormatsInstalled) {
|
||||||
|
command.add("weasyprint");
|
||||||
|
} else {
|
||||||
|
command.add("wkhtmltopdf");
|
||||||
|
command.add("--enable-local-file-access");
|
||||||
|
command.add("--load-error-handling");
|
||||||
|
command.add("ignore");
|
||||||
|
command.add("--load-media-error-handling");
|
||||||
|
command.add("ignore");
|
||||||
|
command.add("--zoom");
|
||||||
|
command.add(String.valueOf(request.getZoom()));
|
||||||
|
|
||||||
|
// if custom zoom add zoom style direct to html
|
||||||
|
// https://github.com/wkhtmltopdf/wkhtmltopdf/issues/4900
|
||||||
|
if (request.getZoom() != 1.0) {
|
||||||
|
String htmlContent = new String(Files.readAllBytes(tempInputFile));
|
||||||
|
|
||||||
|
String zoomStyle = "<style>body { zoom: " + request.getZoom() + "; }</style>";
|
||||||
|
// Check for <head> tag, add style tag to associated tag
|
||||||
|
if (htmlContent.contains("<head>")) {
|
||||||
|
htmlContent = htmlContent.replace("<head>", "<head>" + zoomStyle);
|
||||||
|
} else if (htmlContent.contains("<html>")) {
|
||||||
|
// If no <head> tag, but <html> tag exists
|
||||||
|
htmlContent = htmlContent.replace("<html>", "<html>" + zoomStyle);
|
||||||
|
} else {
|
||||||
|
// If neither <head> nor <html> tags exist
|
||||||
|
htmlContent = zoomStyle + htmlContent;
|
||||||
|
}
|
||||||
|
// rewrite new html to file
|
||||||
|
Files.write(tempInputFile, htmlContent.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getPageWidth() != null) {
|
||||||
|
command.add("--page-width");
|
||||||
|
command.add(request.getPageWidth() + "cm");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getPageHeight() != null) {
|
||||||
|
command.add("--page-height");
|
||||||
|
command.add(request.getPageHeight() + "cm");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getMarginTop() != null) {
|
||||||
|
command.add("--margin-top");
|
||||||
|
command.add(request.getMarginTop() + "mm");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeat similar pattern for marginBottom, marginLeft, marginRight
|
||||||
|
|
||||||
|
if ("Yes".equalsIgnoreCase(request.getPrintBackground())) {
|
||||||
|
command.add("--background");
|
||||||
|
} else {
|
||||||
|
command.add("--no-background");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("Yes".equalsIgnoreCase(request.getDefaultHeader())) {
|
||||||
|
command.add("--default-header");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("print".equalsIgnoreCase(request.getCssMediaType())) {
|
||||||
|
command.add("--print-media-type");
|
||||||
|
} else if ("screen".equalsIgnoreCase(request.getCssMediaType())) {
|
||||||
|
command.add("--no-print-media-type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
command.add(tempOutputFile.toString());
|
command.add(tempOutputFile.toString());
|
||||||
ProcessExecutorResult returnCode;
|
ProcessExecutorResult returnCode;
|
||||||
if (fileName.endsWith(".zip")) {
|
if (fileName.endsWith(".zip")) {
|
||||||
|
|
||||||
|
if (htmlFormatsInstalled) {
|
||||||
|
// command.add(1, "--allow");
|
||||||
|
// command.add(2, tempInputFile.getParent().toString());
|
||||||
|
}
|
||||||
returnCode =
|
returnCode =
|
||||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
|
||||||
.runCommandWithOutputHandling(
|
.runCommandWithOutputHandling(
|
||||||
@ -46,7 +125,13 @@ public class FileToPdf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pdfBytes = Files.readAllBytes(tempOutputFile);
|
pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||||
|
if (pdfBytes.length < 1) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
||||||
// Clean up temporary files
|
// Clean up temporary files
|
||||||
Files.delete(tempOutputFile);
|
Files.delete(tempOutputFile);
|
||||||
Files.delete(tempInputFile);
|
Files.delete(tempInputFile);
|
||||||
@ -61,7 +146,8 @@ public class FileToPdf {
|
|||||||
|
|
||||||
private static Path unzipAndGetMainHtml(byte[] fileBytes) throws IOException {
|
private static Path unzipAndGetMainHtml(byte[] fileBytes) throws IOException {
|
||||||
Path tempDirectory = Files.createTempDirectory("unzipped_");
|
Path tempDirectory = Files.createTempDirectory("unzipped_");
|
||||||
try (ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(fileBytes))) {
|
try (ZipInputStream zipIn =
|
||||||
|
ZipSecurity.createHardenedInputStream(new ByteArrayInputStream(fileBytes))) {
|
||||||
ZipEntry entry = zipIn.getNextEntry();
|
ZipEntry entry = zipIn.getNextEntry();
|
||||||
while (entry != null) {
|
while (entry != null) {
|
||||||
Path filePath = tempDirectory.resolve(entry.getName());
|
Path filePath = tempDirectory.resolve(entry.getName());
|
||||||
@ -89,7 +175,7 @@ public class FileToPdf {
|
|||||||
|
|
||||||
// Prioritize 'index.html' if it exists, otherwise use the first .html file
|
// Prioritize 'index.html' if it exists, otherwise use the first .html file
|
||||||
for (Path htmlFile : htmlFiles) {
|
for (Path htmlFile : htmlFiles) {
|
||||||
if (htmlFile.getFileName().toString().equals("index.html")) {
|
if ("index.html".equals(htmlFile.getFileName().toString())) {
|
||||||
return htmlFile;
|
return htmlFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,4 +183,37 @@ public class FileToPdf {
|
|||||||
return htmlFiles.get(0);
|
return htmlFiles.get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] convertBookTypeToPdf(byte[] bytes, String originalFilename)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
if (originalFilename == null || originalFilename.lastIndexOf('.') == -1) {
|
||||||
|
throw new IllegalArgumentException("Invalid original filename.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf('.'));
|
||||||
|
List<String> command = new ArrayList<>();
|
||||||
|
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||||
|
Path tempInputFile = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create temp file with appropriate extension
|
||||||
|
tempInputFile = Files.createTempFile("input_", fileExtension);
|
||||||
|
Files.write(tempInputFile, bytes);
|
||||||
|
|
||||||
|
command.add("ebook-convert");
|
||||||
|
command.add(tempInputFile.toString());
|
||||||
|
command.add(tempOutputFile.toString());
|
||||||
|
ProcessExecutorResult returnCode =
|
||||||
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.CALIBRE)
|
||||||
|
.runCommandWithOutputHandling(command);
|
||||||
|
|
||||||
|
return Files.readAllBytes(tempOutputFile);
|
||||||
|
} finally {
|
||||||
|
// Clean up temporary files
|
||||||
|
if (tempInputFile != null) {
|
||||||
|
Files.deleteIfExists(tempInputFile);
|
||||||
|
}
|
||||||
|
Files.deleteIfExists(tempOutputFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -17,8 +16,19 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.github.pixee.security.HostValidator;
|
||||||
|
import io.github.pixee.security.Urls;
|
||||||
|
|
||||||
public class GeneralUtils {
|
public class GeneralUtils {
|
||||||
|
|
||||||
|
public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
|
||||||
|
File tempFile = Files.createTempFile("temp", null).toFile();
|
||||||
|
try (FileOutputStream os = new FileOutputStream(tempFile)) {
|
||||||
|
os.write(multipartFile.getBytes());
|
||||||
|
}
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
|
||||||
public static void deleteDirectory(Path path) throws IOException {
|
public static void deleteDirectory(Path path) throws IOException {
|
||||||
Files.walkFileTree(
|
Files.walkFileTree(
|
||||||
path,
|
path,
|
||||||
@ -49,7 +59,8 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
public static boolean isValidURL(String urlStr) {
|
public static boolean isValidURL(String urlStr) {
|
||||||
try {
|
try {
|
||||||
new URL(urlStr);
|
Urls.create(
|
||||||
|
urlStr, Urls.HTTP_PROTOCOLS, HostValidator.DENY_COMMON_INFRASTRUCTURE_TARGETS);
|
||||||
return true;
|
return true;
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
return false;
|
return false;
|
||||||
@ -112,7 +123,7 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
// loop through the page order array
|
// loop through the page order array
|
||||||
for (String element : pageOrderArr) {
|
for (String element : pageOrderArr) {
|
||||||
if (element.equalsIgnoreCase("all")) {
|
if ("all".equalsIgnoreCase(element)) {
|
||||||
for (int i = 0; i < totalPages; i++) {
|
for (int i = 0; i < totalPages; i++) {
|
||||||
newPageOrder.add(i);
|
newPageOrder.add(i);
|
||||||
}
|
}
|
||||||
@ -127,11 +138,11 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
if (element.contains("n")) {
|
if (element.contains("n")) {
|
||||||
String[] parts = element.split("n");
|
String[] parts = element.split("n");
|
||||||
if (!parts[0].equals("") && parts[0] != null) {
|
if (!"".equals(parts[0]) && parts[0] != null) {
|
||||||
coefficient = Integer.parseInt(parts[0]);
|
coefficient = Integer.parseInt(parts[0]);
|
||||||
coefficientExists = true;
|
coefficientExists = true;
|
||||||
}
|
}
|
||||||
if (parts.length > 1 && !parts[1].equals("") && parts[1] != null) {
|
if (parts.length > 1 && !"".equals(parts[1]) && parts[1] != null) {
|
||||||
constant = Integer.parseInt(parts[1]);
|
constant = Integer.parseInt(parts[1]);
|
||||||
constantExists = true;
|
constantExists = true;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ import org.springframework.http.MediaType;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.github.pixee.security.Filenames;
|
||||||
|
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
|
||||||
public class PDFToFile {
|
public class PDFToFile {
|
||||||
@ -32,7 +34,7 @@ public class PDFToFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the original PDF file name without the extension
|
// Get the original PDF file name without the extension
|
||||||
String originalPdfFileName = inputFile.getOriginalFilename();
|
String originalPdfFileName = Filenames.toSimpleFileName(inputFile.getOriginalFilename());
|
||||||
String pdfBaseName = originalPdfFileName.substring(0, originalPdfFileName.lastIndexOf('.'));
|
String pdfBaseName = originalPdfFileName.substring(0, originalPdfFileName.lastIndexOf('.'));
|
||||||
|
|
||||||
// Validate output format
|
// Validate output format
|
||||||
@ -87,7 +89,7 @@ public class PDFToFile {
|
|||||||
if (outputFiles.size() == 1) {
|
if (outputFiles.size() == 1) {
|
||||||
// Return single output file
|
// Return single output file
|
||||||
File outputFile = outputFiles.get(0);
|
File outputFile = outputFiles.get(0);
|
||||||
if (outputFormat.equals("txt:Text")) {
|
if ("txt:Text".equals(outputFormat)) {
|
||||||
outputFormat = "txt";
|
outputFormat = "txt";
|
||||||
}
|
}
|
||||||
fileName = pdfBaseName + "." + outputFormat;
|
fileName = pdfBaseName + "." + outputFormat;
|
||||||
|
@ -2,9 +2,10 @@ package stirling.software.SPDF.utils;
|
|||||||
|
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
@ -16,10 +17,16 @@ import javax.imageio.ImageWriteParam;
|
|||||||
import javax.imageio.ImageWriter;
|
import javax.imageio.ImageWriter;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDResources;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
|
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||||
@ -30,7 +37,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import stirling.software.SPDF.pdf.ImageFinder;
|
import io.github.pixee.security.Filenames;
|
||||||
|
|
||||||
public class PdfUtils {
|
public class PdfUtils {
|
||||||
|
|
||||||
@ -61,6 +68,23 @@ public class PdfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<RenderedImage> getAllImages(PDResources resources) throws IOException {
|
||||||
|
List<RenderedImage> images = new ArrayList<>();
|
||||||
|
|
||||||
|
for (COSName name : resources.getXObjectNames()) {
|
||||||
|
PDXObject object = resources.getXObject(name);
|
||||||
|
|
||||||
|
if (object instanceof PDImageXObject) {
|
||||||
|
images.add(((PDImageXObject) object).getImage());
|
||||||
|
|
||||||
|
} else if (object instanceof PDFormXObject) {
|
||||||
|
images.addAll(getAllImages(((PDFormXObject) object).getResources()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean hasImages(PDDocument document, String pagesToCheck) throws IOException {
|
public static boolean hasImages(PDDocument document, String pagesToCheck) throws IOException {
|
||||||
String[] pageOrderArr = pagesToCheck.split(",");
|
String[] pageOrderArr = pagesToCheck.split(",");
|
||||||
List<Integer> pageList =
|
List<Integer> pageList =
|
||||||
@ -93,9 +117,7 @@ public class PdfUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasImagesOnPage(PDPage page) throws IOException {
|
public static boolean hasImagesOnPage(PDPage page) throws IOException {
|
||||||
ImageFinder imageFinder = new ImageFinder(page);
|
return getAllImages(page.getResources()).size() > 0;
|
||||||
imageFinder.processPage(page);
|
|
||||||
return imageFinder.hasImages();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasTextOnPage(PDPage page, String phrase) throws IOException {
|
public static boolean hasTextOnPage(PDPage page, String phrase) throws IOException {
|
||||||
@ -112,7 +134,7 @@ public class PdfUtils {
|
|||||||
PDFTextStripper textStripper = new PDFTextStripper();
|
PDFTextStripper textStripper = new PDFTextStripper();
|
||||||
String pdfText = "";
|
String pdfText = "";
|
||||||
|
|
||||||
if (pagesToCheck == null || pagesToCheck.equals("all")) {
|
if (pagesToCheck == null || "all".equals(pagesToCheck)) {
|
||||||
pdfText = textStripper.getText(pdfDocument);
|
pdfText = textStripper.getText(pdfDocument);
|
||||||
} else {
|
} else {
|
||||||
// remove whitespaces
|
// remove whitespaces
|
||||||
@ -190,7 +212,7 @@ public class PdfUtils {
|
|||||||
int DPI,
|
int DPI,
|
||||||
String filename)
|
String filename)
|
||||||
throws IOException, Exception {
|
throws IOException, Exception {
|
||||||
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
|
try (PDDocument document = Loader.loadPDF(inputStream)) {
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
int pageCount = document.getNumberOfPages();
|
int pageCount = document.getNumberOfPages();
|
||||||
|
|
||||||
@ -198,8 +220,8 @@ public class PdfUtils {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
if (singleImage) {
|
if (singleImage) {
|
||||||
if (imageType.toLowerCase().equals("tiff")
|
if ("tiff".equals(imageType.toLowerCase())
|
||||||
|| imageType.toLowerCase().equals("tif")) {
|
|| "tif".equals(imageType.toLowerCase())) {
|
||||||
// Write the images to the output stream as a TIFF with multiple frames
|
// Write the images to the output stream as a TIFF with multiple frames
|
||||||
ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
|
ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
|
||||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
ImageWriteParam param = writer.getDefaultWriteParam();
|
||||||
@ -279,7 +301,7 @@ public class PdfUtils {
|
|||||||
try (PDDocument doc = new PDDocument()) {
|
try (PDDocument doc = new PDDocument()) {
|
||||||
for (MultipartFile file : files) {
|
for (MultipartFile file : files) {
|
||||||
String contentType = file.getContentType();
|
String contentType = file.getContentType();
|
||||||
String originalFilename = file.getOriginalFilename();
|
String originalFilename = Filenames.toSimpleFileName(file.getOriginalFilename());
|
||||||
if (originalFilename != null
|
if (originalFilename != null
|
||||||
&& (originalFilename.toLowerCase().endsWith(".tiff")
|
&& (originalFilename.toLowerCase().endsWith(".tiff")
|
||||||
|| originalFilename.toLowerCase().endsWith(".tif"))) {
|
|| originalFilename.toLowerCase().endsWith(".tif"))) {
|
||||||
@ -300,7 +322,7 @@ public class PdfUtils {
|
|||||||
ImageProcessingUtils.convertColorType(image, colorType);
|
ImageProcessingUtils.convertColorType(image, colorType);
|
||||||
// Use JPEGFactory if it's JPEG since JPEG is lossy
|
// Use JPEGFactory if it's JPEG since JPEG is lossy
|
||||||
PDImageXObject pdImage =
|
PDImageXObject pdImage =
|
||||||
(contentType != null && contentType.equals("image/jpeg"))
|
(contentType != null && "image/jpeg".equals(contentType))
|
||||||
? JPEGFactory.createFromImage(doc, convertedImage)
|
? JPEGFactory.createFromImage(doc, convertedImage)
|
||||||
: LosslessFactory.createFromImage(doc, convertedImage);
|
: LosslessFactory.createFromImage(doc, convertedImage);
|
||||||
addImageToDocument(doc, pdImage, fitOption, autoRotate);
|
addImageToDocument(doc, pdImage, fitOption, autoRotate);
|
||||||
@ -335,7 +357,8 @@ public class PdfUtils {
|
|||||||
float pageWidth = page.getMediaBox().getWidth();
|
float pageWidth = page.getMediaBox().getWidth();
|
||||||
float pageHeight = page.getMediaBox().getHeight();
|
float pageHeight = page.getMediaBox().getHeight();
|
||||||
|
|
||||||
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
|
try (PDPageContentStream contentStream =
|
||||||
|
new PDPageContentStream(doc, page, AppendMode.APPEND, true, true)) {
|
||||||
if ("fillPage".equals(fitOption) || "fitDocumentToImage".equals(fitOption)) {
|
if ("fillPage".equals(fitOption) || "fitDocumentToImage".equals(fitOption)) {
|
||||||
contentStream.drawImage(image, 0, 0, pageWidth, pageHeight);
|
contentStream.drawImage(image, 0, 0, pageWidth, pageHeight);
|
||||||
} else if ("maintainAspectRatio".equals(fitOption)) {
|
} else if ("maintainAspectRatio".equals(fitOption)) {
|
||||||
@ -368,7 +391,7 @@ public class PdfUtils {
|
|||||||
byte[] pdfBytes, byte[] imageBytes, float x, float y, boolean everyPage)
|
byte[] pdfBytes, byte[] imageBytes, float x, float y, boolean everyPage)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes));
|
PDDocument document = Loader.loadPDF(pdfBytes);
|
||||||
|
|
||||||
// Get the first page of the PDF
|
// Get the first page of the PDF
|
||||||
int pages = document.getNumberOfPages();
|
int pages = document.getNumberOfPages();
|
||||||
@ -376,7 +399,7 @@ public class PdfUtils {
|
|||||||
PDPage page = document.getPage(i);
|
PDPage page = document.getPage(i);
|
||||||
try (PDPageContentStream contentStream =
|
try (PDPageContentStream contentStream =
|
||||||
new PDPageContentStream(
|
new PDPageContentStream(
|
||||||
document, page, PDPageContentStream.AppendMode.APPEND, true)) {
|
document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
|
||||||
// Create an image object from the image bytes
|
// Create an image object from the image bytes
|
||||||
PDImageXObject image = PDImageXObject.createFromByteArray(document, imageBytes, "");
|
PDImageXObject image = PDImageXObject.createFromByteArray(document, imageBytes, "");
|
||||||
// Draw the image onto the page at the specified x and y coordinates
|
// Draw the image onto the page at the specified x and y coordinates
|
||||||
|
@ -4,26 +4,41 @@ import java.io.BufferedReader;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import io.github.pixee.security.BoundedLineReader;
|
||||||
|
|
||||||
public class ProcessExecutor {
|
public class ProcessExecutor {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ProcessExecutor.class);
|
||||||
|
|
||||||
public enum Processes {
|
public enum Processes {
|
||||||
LIBRE_OFFICE,
|
LIBRE_OFFICE,
|
||||||
OCR_MY_PDF,
|
OCR_MY_PDF,
|
||||||
PYTHON_OPENCV,
|
PYTHON_OPENCV,
|
||||||
GHOSTSCRIPT,
|
GHOSTSCRIPT,
|
||||||
WEASYPRINT
|
WEASYPRINT,
|
||||||
|
INSTALL_APP,
|
||||||
|
CALIBRE
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<Processes, ProcessExecutor> instances = new ConcurrentHashMap<>();
|
private static final Map<Processes, ProcessExecutor> instances = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public static ProcessExecutor getInstance(Processes processType) {
|
public static ProcessExecutor getInstance(Processes processType) {
|
||||||
|
return getInstance(processType, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProcessExecutor getInstance(Processes processType, boolean liveUpdates) {
|
||||||
return instances.computeIfAbsent(
|
return instances.computeIfAbsent(
|
||||||
processType,
|
processType,
|
||||||
key -> {
|
key -> {
|
||||||
@ -34,15 +49,32 @@ public class ProcessExecutor {
|
|||||||
case PYTHON_OPENCV -> 8;
|
case PYTHON_OPENCV -> 8;
|
||||||
case GHOSTSCRIPT -> 16;
|
case GHOSTSCRIPT -> 16;
|
||||||
case WEASYPRINT -> 16;
|
case WEASYPRINT -> 16;
|
||||||
|
case INSTALL_APP -> 1;
|
||||||
|
case CALIBRE -> 1;
|
||||||
};
|
};
|
||||||
return new ProcessExecutor(semaphoreLimit);
|
|
||||||
|
long timeoutMinutes =
|
||||||
|
switch (key) {
|
||||||
|
case LIBRE_OFFICE -> 30;
|
||||||
|
case OCR_MY_PDF -> 30;
|
||||||
|
case PYTHON_OPENCV -> 30;
|
||||||
|
case GHOSTSCRIPT -> 5;
|
||||||
|
case WEASYPRINT -> 30;
|
||||||
|
case INSTALL_APP -> 60;
|
||||||
|
case CALIBRE -> 30;
|
||||||
|
};
|
||||||
|
return new ProcessExecutor(semaphoreLimit, liveUpdates, timeoutMinutes);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Semaphore semaphore;
|
private final Semaphore semaphore;
|
||||||
|
private final boolean liveUpdates;
|
||||||
|
private long timeoutDuration;
|
||||||
|
|
||||||
private ProcessExecutor(int semaphoreLimit) {
|
private ProcessExecutor(int semaphoreLimit, boolean liveUpdates, long timeout) {
|
||||||
this.semaphore = new Semaphore(semaphoreLimit);
|
this.semaphore = new Semaphore(semaphoreLimit);
|
||||||
|
this.liveUpdates = liveUpdates;
|
||||||
|
this.timeoutDuration = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProcessExecutorResult runCommandWithOutputHandling(List<String> command)
|
public ProcessExecutorResult runCommandWithOutputHandling(List<String> command)
|
||||||
@ -52,12 +84,12 @@ public class ProcessExecutor {
|
|||||||
|
|
||||||
public ProcessExecutorResult runCommandWithOutputHandling(
|
public ProcessExecutorResult runCommandWithOutputHandling(
|
||||||
List<String> command, File workingDirectory) throws IOException, InterruptedException {
|
List<String> command, File workingDirectory) throws IOException, InterruptedException {
|
||||||
int exitCode = 1;
|
|
||||||
String messages = "";
|
String messages = "";
|
||||||
|
int exitCode = 1;
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
System.out.print("Running command: " + String.join(" ", command));
|
logger.info("Running command: " + String.join(" ", command));
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||||
|
|
||||||
// Use the working directory if it's set
|
// Use the working directory if it's set
|
||||||
@ -79,9 +111,16 @@ public class ProcessExecutor {
|
|||||||
process.getErrorStream(),
|
process.getErrorStream(),
|
||||||
StandardCharsets.UTF_8))) {
|
StandardCharsets.UTF_8))) {
|
||||||
String line;
|
String line;
|
||||||
while ((line = errorReader.readLine()) != null) {
|
while ((line =
|
||||||
|
BoundedLineReader.readLine(
|
||||||
|
errorReader, 5_000_000))
|
||||||
|
!= null) {
|
||||||
errorLines.add(line);
|
errorLines.add(line);
|
||||||
|
if (liveUpdates) logger.info(line);
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedIOException e) {
|
||||||
|
logger.warn(
|
||||||
|
"Error reader thread was interrupted due to timeout.");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -96,9 +135,16 @@ public class ProcessExecutor {
|
|||||||
process.getInputStream(),
|
process.getInputStream(),
|
||||||
StandardCharsets.UTF_8))) {
|
StandardCharsets.UTF_8))) {
|
||||||
String line;
|
String line;
|
||||||
while ((line = outputReader.readLine()) != null) {
|
while ((line =
|
||||||
|
BoundedLineReader.readLine(
|
||||||
|
outputReader, 5_000_000))
|
||||||
|
!= null) {
|
||||||
outputLines.add(line);
|
outputLines.add(line);
|
||||||
|
if (liveUpdates) logger.info(line);
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedIOException e) {
|
||||||
|
logger.warn(
|
||||||
|
"Error reader thread was interrupted due to timeout.");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -108,29 +154,42 @@ public class ProcessExecutor {
|
|||||||
outputReaderThread.start();
|
outputReaderThread.start();
|
||||||
|
|
||||||
// Wait for the conversion process to complete
|
// Wait for the conversion process to complete
|
||||||
exitCode = process.waitFor();
|
boolean finished = process.waitFor(timeoutDuration, TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
if (!finished) {
|
||||||
|
// Terminate the process
|
||||||
|
process.destroy();
|
||||||
|
// Interrupt the reader threads
|
||||||
|
errorReaderThread.interrupt();
|
||||||
|
outputReaderThread.interrupt();
|
||||||
|
throw new IOException("Process timeout exceeded.");
|
||||||
|
}
|
||||||
|
exitCode = process.exitValue();
|
||||||
// Wait for the reader threads to finish
|
// Wait for the reader threads to finish
|
||||||
errorReaderThread.join();
|
errorReaderThread.join();
|
||||||
outputReaderThread.join();
|
outputReaderThread.join();
|
||||||
|
|
||||||
if (outputLines.size() > 0) {
|
if (!liveUpdates) {
|
||||||
String outputMessage = String.join("\n", outputLines);
|
if (outputLines.size() > 0) {
|
||||||
messages += outputMessage;
|
String outputMessage = String.join("\n", outputLines);
|
||||||
System.out.println("Command output:\n" + outputMessage);
|
messages += outputMessage;
|
||||||
}
|
logger.info("Command output:\n" + outputMessage);
|
||||||
|
|
||||||
if (errorLines.size() > 0) {
|
|
||||||
String errorMessage = String.join("\n", errorLines);
|
|
||||||
messages += errorMessage;
|
|
||||||
System.out.println("Command error output:\n" + errorMessage);
|
|
||||||
if (exitCode != 0) {
|
|
||||||
throw new IOException(
|
|
||||||
"Command process failed with exit code "
|
|
||||||
+ exitCode
|
|
||||||
+ ". Error message: "
|
|
||||||
+ errorMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (errorLines.size() > 0) {
|
||||||
|
String errorMessage = String.join("\n", errorLines);
|
||||||
|
messages += errorMessage;
|
||||||
|
logger.warn("Command error output:\n" + errorMessage);
|
||||||
|
if (exitCode != 0) {
|
||||||
|
throw new IOException(
|
||||||
|
"Command process failed with exit code "
|
||||||
|
+ exitCode
|
||||||
|
+ ". Error message: "
|
||||||
|
+ errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (exitCode != 0) {
|
||||||
|
throw new IOException("Command process failed with exit code " + exitCode);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
|
@ -12,6 +12,8 @@ import org.springframework.http.MediaType;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.github.pixee.security.Filenames;
|
||||||
|
|
||||||
public class WebResponseUtils {
|
public class WebResponseUtils {
|
||||||
|
|
||||||
public static ResponseEntity<byte[]> boasToWebResponse(
|
public static ResponseEntity<byte[]> boasToWebResponse(
|
||||||
@ -26,7 +28,7 @@ public class WebResponseUtils {
|
|||||||
|
|
||||||
public static ResponseEntity<byte[]> multiPartFileToWebResponse(MultipartFile file)
|
public static ResponseEntity<byte[]> multiPartFileToWebResponse(MultipartFile file)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String fileName = file.getOriginalFilename();
|
String fileName = Filenames.toSimpleFileName(file.getOriginalFilename());
|
||||||
MediaType mediaType = MediaType.parseMediaType(file.getContentType());
|
MediaType mediaType = MediaType.parseMediaType(file.getContentType());
|
||||||
|
|
||||||
byte[] bytes = file.getBytes();
|
byte[] bytes = file.getBytes();
|
||||||
|
@ -44,7 +44,8 @@ blue=Blue
|
|||||||
custom=Custom...
|
custom=Custom...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=Credentials changed!
|
changedCredsMessage=Credentials changed!
|
||||||
notAuthenticatedMessage=User not authenticated.
|
notAuthenticatedMessage=User not authenticated.
|
||||||
userNotFoundMessage=User not found.
|
userNotFoundMessage=User not found.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ 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
|
split-by-sections.tags=Section Split, Divide, Customize
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML To PDF
|
|||||||
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
HTMLToPDF.submit=Convert
|
HTMLToPDF.submit=Convert
|
||||||
HTMLToPDF.credit=Uses WeasyPrint
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=Sanitize PDF
|
sanitizePDF.title=Sanitize PDF
|
||||||
sanitizePDF.header=Sanitize a PDF file
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
@ -44,7 +44,8 @@ blue=Синьо
|
|||||||
custom=Персонализиране...
|
custom=Персонализиране...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=Идентификационните данни са променени!
|
changedCredsMessage=Идентификационните данни са променени!
|
||||||
notAuthenticatedMessage=Потребителят не е автентикиран.
|
notAuthenticatedMessage=Потребителят не е автентикиран.
|
||||||
userNotFoundMessage=Потребителят не е намерен
|
userNotFoundMessage=Потребителят не е намерен
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ 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
|
split-by-sections.tags=Section Split, Divide, Customize
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML към PDF
|
|||||||
HTMLToPDF.help=Приема HTML файлове и ZIP файлове, съдържащи html/css/изображения и т.н
|
HTMLToPDF.help=Приема HTML файлове и ZIP файлове, съдържащи html/css/изображения и т.н
|
||||||
HTMLToPDF.submit=Преобразуване
|
HTMLToPDF.submit=Преобразуване
|
||||||
HTMLToPDF.credit=Използва WeasyPrint
|
HTMLToPDF.credit=Използва WeasyPrint
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=Дезинфектирай PDF
|
sanitizePDF.title=Дезинфектирай PDF
|
||||||
sanitizePDF.header=Дезинфектира PDF файл
|
sanitizePDF.header=Дезинфектира PDF файл
|
||||||
|
@ -44,7 +44,8 @@ blue=Blau
|
|||||||
custom=Personalitzat...
|
custom=Personalitzat...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=Credentials changed!
|
changedCredsMessage=Credentials changed!
|
||||||
notAuthenticatedMessage=User not authenticated.
|
notAuthenticatedMessage=User not authenticated.
|
||||||
userNotFoundMessage=User not found.
|
userNotFoundMessage=User not found.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ 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
|
split-by-sections.tags=Section Split, Divide, Customize
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML To PDF
|
|||||||
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
HTMLToPDF.submit=Convert
|
HTMLToPDF.submit=Convert
|
||||||
HTMLToPDF.credit=Uses WeasyPrint
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=Sanitize PDF
|
sanitizePDF.title=Sanitize PDF
|
||||||
sanitizePDF.header=Sanitize a PDF file
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
||||||
@ -44,7 +44,8 @@ blue=Blau
|
|||||||
custom=benutzerdefiniert...
|
custom=benutzerdefiniert...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=Anmeldedaten geändert!
|
changedCredsMessage=Anmeldedaten geändert!
|
||||||
notAuthenticatedMessage=Benutzer nicht authentifiziert.
|
notAuthenticatedMessage=Benutzer nicht authentifiziert.
|
||||||
userNotFoundMessage=Benutzer nicht gefunden.
|
userNotFoundMessage=Benutzer nicht gefunden.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -340,22 +342,22 @@ HTMLToPDF.tags=markup,web-content,transformation,convert
|
|||||||
|
|
||||||
home.MarkdownToPDF.title=Markdown zu PDF
|
home.MarkdownToPDF.title=Markdown zu PDF
|
||||||
home.MarkdownToPDF.desc=Konvertiert jede Markdown-Datei zu PDF
|
home.MarkdownToPDF.desc=Konvertiert jede Markdown-Datei zu PDF
|
||||||
MarkdownToPDF.tags=markup,web-content,transformation,convert
|
MarkdownToPDF.tags=markup,web-content,transformation,konvertieren
|
||||||
|
|
||||||
|
|
||||||
home.getPdfInfo.title=Alle Informationen anzeigen
|
home.getPdfInfo.title=Alle Informationen anzeigen
|
||||||
home.getPdfInfo.desc=Erfasst alle möglichen Informationen in einer PDF
|
home.getPdfInfo.desc=Erfasst alle möglichen Informationen in einer PDF
|
||||||
getPdfInfo.tags=infomation,data,stats,statistics
|
getPdfInfo.tags=infomation,daten,statistik
|
||||||
|
|
||||||
|
|
||||||
home.extractPage.title=Seite(n) extrahieren
|
home.extractPage.title=Seite(n) extrahieren
|
||||||
home.extractPage.desc=Extrahiert ausgewählte Seiten aus einer PDF
|
home.extractPage.desc=Extrahiert ausgewählte Seiten aus einer PDF
|
||||||
extractPage.tags=extract
|
extractPage.tags=extrahieren
|
||||||
|
|
||||||
|
|
||||||
home.PdfToSinglePage.title=PDF zu einer Seite zusammenfassen
|
home.PdfToSinglePage.title=PDF zu einer Seite zusammenfassen
|
||||||
home.PdfToSinglePage.desc=Fügt alle PDF-Seiten zu einer einzigen großen Seite zusammen
|
home.PdfToSinglePage.desc=Fügt alle PDF-Seiten zu einer einzigen großen Seite zusammen
|
||||||
PdfToSinglePage.tags=single page
|
PdfToSinglePage.tags=einzelseite
|
||||||
|
|
||||||
|
|
||||||
home.showJS.title=Javascript anzeigen
|
home.showJS.title=Javascript anzeigen
|
||||||
@ -363,26 +365,31 @@ home.showJS.desc=Alle Javascript Funktionen in einer PDF anzeigen
|
|||||||
showJS.tags=JS
|
showJS.tags=JS
|
||||||
|
|
||||||
home.autoRedact.title=Automatisch zensieren/schwärzen
|
home.autoRedact.title=Automatisch zensieren/schwärzen
|
||||||
home.autoRedact.desc=Automatisches zensierten (Schwärzen) von Text in einer PDF-Datei basierend auf dem eingegebenen Text
|
home.autoRedact.desc=Automatisches Zensieren (Schwärzen) von Text in einer PDF-Datei basierend auf dem eingegebenen Text
|
||||||
showJS.tags=JS
|
showJS.tags=zensieren,schwärzen
|
||||||
|
|
||||||
home.tableExtraxt.title=Tabelle extrahieren
|
home.tableExtraxt.title=Tabelle extrahieren
|
||||||
home.tableExtraxt.desc=Tabelle aus PDF in CSV extrahieren
|
home.tableExtraxt.desc=Tabelle aus PDF in CSV extrahieren
|
||||||
tableExtraxt.tags=CSV
|
tableExtraxt.tags=CSV
|
||||||
|
|
||||||
|
|
||||||
home.autoSizeSplitPDF.title=Auto Split by Size/Count
|
home.autoSizeSplitPDF.title=Teilen nach Größe/Anzahl
|
||||||
home.autoSizeSplitPDF.desc=Split a single PDF into multiple documents based on size, page count, or document count
|
home.autoSizeSplitPDF.desc=Teilen Sie ein einzelnes PDF basierend auf Größe, Seitenanzahl oder Dokumentanzahl in mehrere Dokumente auf
|
||||||
autoSizeSplitPDF.tags=pdf,split,document,organization
|
autoSizeSplitPDF.tags=pdf,teilen,dokument,organisation
|
||||||
|
|
||||||
|
|
||||||
home.overlay-pdfs.title=Overlay PDFs
|
home.overlay-pdfs.title=PDF mit Overlay versehen
|
||||||
home.overlay-pdfs.desc=Overlays PDFs on-top of another PDF
|
home.overlay-pdfs.desc=Überlagert eine PDF über eine andere PDF
|
||||||
overlay-pdfs.tags=Overlay
|
overlay-pdfs.tags=overlay,überlagern
|
||||||
|
|
||||||
|
home.split-by-sections.title=PDF in Abschnitte teilen
|
||||||
|
home.split-by-sections.desc=Teilen Sie jede Seite einer PDF-Datei in kleinere horizontale und vertikale Abschnitte auf
|
||||||
|
split-by-sections.tags=abschnitte,teilen,bearbeiten
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
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
|
|
||||||
split-by-sections.tags=Section Split, Divide, Customize
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
@ -408,7 +415,7 @@ autoRedact.useRegexLabel=Regex verwenden
|
|||||||
autoRedact.wholeWordSearchLabel=Ganzes Wort suchen
|
autoRedact.wholeWordSearchLabel=Ganzes Wort suchen
|
||||||
autoRedact.customPaddingLabel=Benutzerdefinierte Extra-Padding
|
autoRedact.customPaddingLabel=Benutzerdefinierte Extra-Padding
|
||||||
autoRedact.convertPDFToImageLabel=PDF in PDF-Bild konvertieren (zum Entfernen von Text hinter dem Kasten)
|
autoRedact.convertPDFToImageLabel=PDF in PDF-Bild konvertieren (zum Entfernen von Text hinter dem Kasten)
|
||||||
autoRedact.submitButton=zensieren
|
autoRedact.submitButton=Zensieren
|
||||||
|
|
||||||
|
|
||||||
#showJS
|
#showJS
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML zu PDF
|
|||||||
HTMLToPDF.help=Akzeptiert HTML-Dateien und ZIPs mit html/css/images etc.
|
HTMLToPDF.help=Akzeptiert HTML-Dateien und ZIPs mit html/css/images etc.
|
||||||
HTMLToPDF.submit=Konvertieren
|
HTMLToPDF.submit=Konvertieren
|
||||||
HTMLToPDF.credit=Verwendet WeasyPrint
|
HTMLToPDF.credit=Verwendet WeasyPrint
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=PDF Bereinigen
|
sanitizePDF.title=PDF Bereinigen
|
||||||
sanitizePDF.header=PDF Bereinigen
|
sanitizePDF.header=PDF Bereinigen
|
||||||
@ -572,9 +609,9 @@ removeBlanks.submit=Leere Seiten entfernen
|
|||||||
|
|
||||||
|
|
||||||
#removeAnnotations
|
#removeAnnotations
|
||||||
removeAnnotations.title=Remove Annotations
|
removeAnnotations.title=Kommentare entfernen
|
||||||
removeAnnotations.header=Remove Annotations
|
removeAnnotations.header=Kommentare entfernen
|
||||||
removeAnnotations.submit=Remove
|
removeAnnotations.submit=Entfernen
|
||||||
|
|
||||||
|
|
||||||
#compare
|
#compare
|
||||||
@ -591,7 +628,7 @@ sign.header=PDFs signieren
|
|||||||
sign.upload=Bild hochladen
|
sign.upload=Bild hochladen
|
||||||
sign.draw=Signatur zeichnen
|
sign.draw=Signatur zeichnen
|
||||||
sign.text=Texteingabe
|
sign.text=Texteingabe
|
||||||
sign.clear=Klar
|
sign.clear=Leeren
|
||||||
sign.add=Signieren
|
sign.add=Signieren
|
||||||
|
|
||||||
|
|
||||||
@ -883,44 +920,44 @@ PDFToXML.submit=Konvertieren
|
|||||||
#PDFToCSV
|
#PDFToCSV
|
||||||
PDFToCSV.title=PDF zu CSV
|
PDFToCSV.title=PDF zu CSV
|
||||||
PDFToCSV.header=PDF zu CSV
|
PDFToCSV.header=PDF zu CSV
|
||||||
PDFToCSV.prompt=Choose page to extract table
|
PDFToCSV.prompt=Seite mit der zu extrahierenden Tabelle wählen
|
||||||
PDFToCSV.submit=Extrakt
|
PDFToCSV.submit=Extrahieren
|
||||||
|
|
||||||
#split-by-size-or-count
|
#split-by-size-or-count
|
||||||
split-by-size-or-count.header=Split PDF by Size or Count
|
split-by-size-or-count.header=PDF nach Größe oder Anzahl teilen
|
||||||
split-by-size-or-count.type.label=Select Split Type
|
split-by-size-or-count.type.label=Teil-Modus wählen
|
||||||
split-by-size-or-count.type.size=By Size
|
split-by-size-or-count.type.size=Nach Größe
|
||||||
split-by-size-or-count.type.pageCount=By Page Count
|
split-by-size-or-count.type.pageCount=Nach Anzahl Seiten
|
||||||
split-by-size-or-count.type.docCount=By Document Count
|
split-by-size-or-count.type.docCount=Nach Anzahl Dokumenten
|
||||||
split-by-size-or-count.value.label=Enter Value
|
split-by-size-or-count.value.label=Wert eingeben
|
||||||
split-by-size-or-count.value.placeholder=Enter size (e.g., 2MB or 3KB) or count (e.g., 5)
|
split-by-size-or-count.value.placeholder=Größe eingeben (z. B.: 2MB oder 3KB) oder Anzahl (z. B.: 5)
|
||||||
split-by-size-or-count.submit=Submit
|
split-by-size-or-count.submit=Erstellen
|
||||||
|
|
||||||
|
|
||||||
#overlay-pdfs
|
#overlay-pdfs
|
||||||
overlay-pdfs.header=Overlay PDF Files
|
overlay-pdfs.header=PDF mit Overlay versehen
|
||||||
overlay-pdfs.baseFile.label=Select Base PDF File
|
overlay-pdfs.baseFile.label=Basis-PDF-Datei auswählen
|
||||||
overlay-pdfs.overlayFiles.label=Select Overlay PDF Files
|
overlay-pdfs.overlayFiles.label=Overlay-PDF-Datei auswählen
|
||||||
overlay-pdfs.mode.label=Select Overlay Mode
|
overlay-pdfs.mode.label=Overlay-Modus auswählen
|
||||||
overlay-pdfs.mode.sequential=Sequential Overlay
|
overlay-pdfs.mode.sequential=Sequentielles Overlay
|
||||||
overlay-pdfs.mode.interleaved=Interleaved Overlay
|
overlay-pdfs.mode.interleaved=Verschachteltes Overlay
|
||||||
overlay-pdfs.mode.fixedRepeat=Fixed Repeat Overlay
|
overlay-pdfs.mode.fixedRepeat=Feste-Wiederholung Overlay
|
||||||
overlay-pdfs.counts.label=Overlay Counts (for Fixed Repeat Mode)
|
overlay-pdfs.counts.label=Overlay Anzahl (für Feste-Wiederholung)
|
||||||
overlay-pdfs.counts.placeholder=Enter comma-separated counts (e.g., 2,3,1)
|
overlay-pdfs.counts.placeholder=Komma-separierte Anzahl eingeben (z. B.: 2,3,1)
|
||||||
overlay-pdfs.position.label=Select Overlay Position
|
overlay-pdfs.position.label=Overlay Position auswählen
|
||||||
overlay-pdfs.position.foreground=Foreground
|
overlay-pdfs.position.foreground=Vordergrund
|
||||||
overlay-pdfs.position.background=Background
|
overlay-pdfs.position.background=Hintergrund
|
||||||
overlay-pdfs.submit=Submit
|
overlay-pdfs.submit=Erstellen
|
||||||
|
|
||||||
|
|
||||||
#split-by-sections
|
#split-by-sections
|
||||||
split-by-sections.title=Split PDF by Sections
|
split-by-sections.title=PDF in Abschnitte teilen
|
||||||
split-by-sections.header=Split PDF into Sections
|
split-by-sections.header=PDF in Abschnitte teilen
|
||||||
split-by-sections.horizontal.label=Horizontal Divisions
|
split-by-sections.horizontal.label=Horizontale Teiler
|
||||||
split-by-sections.vertical.label=Vertical Divisions
|
split-by-sections.vertical.label=Vertikale Teiler
|
||||||
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
|
split-by-sections.horizontal.placeholder=Anzahl horizontaler Teiler eingeben
|
||||||
split-by-sections.vertical.placeholder=Enter number of vertical divisions
|
split-by-sections.vertical.placeholder=Anzahl vertikaler Teiler eingeben
|
||||||
split-by-sections.submit=Split PDF
|
split-by-sections.submit=PDF teilen
|
||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
@ -931,4 +968,3 @@ licenses.module=Module
|
|||||||
licenses.version=Version
|
licenses.version=Version
|
||||||
licenses.license=License
|
licenses.license=License
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,8 @@ blue=\u039C\u03C0\u03BB\u03AD
|
|||||||
custom=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE...
|
custom=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=\u03A4\u03B1 \u03B4\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03AE\u03C1\u03B9\u03B1 \u03AD\u03C7\u03BF\u03C5\u03BD \u03B1\u03BB\u03BB\u03AC\u03BE\u03B5\u03B9!
|
changedCredsMessage=\u03A4\u03B1 \u03B4\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03AE\u03C1\u03B9\u03B1 \u03AD\u03C7\u03BF\u03C5\u03BD \u03B1\u03BB\u03BB\u03AC\u03BE\u03B5\u03B9!
|
||||||
notAuthenticatedMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03B1\u03C5\u03B8\u03B5\u03BD\u03C4\u03B9\u03BA\u03BF\u03C0\u03BF\u03B9\u03B7\u03B8\u03B5\u03AF.
|
notAuthenticatedMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03B1\u03C5\u03B8\u03B5\u03BD\u03C4\u03B9\u03BA\u03BF\u03C0\u03BF\u03B9\u03B7\u03B8\u03B5\u03AF.
|
||||||
userNotFoundMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03B2\u03C1\u03AD\u03B8\u03B7\u03BA\u03B5.
|
userNotFoundMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03B2\u03C1\u03AD\u03B8\u03B7\u03BA\u03B5.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ 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
|
split-by-sections.tags=Section Split, Divide, Customize
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML \u03C3\u03B5 PDF
|
|||||||
HTMLToPDF.help=\u0394\u03AD\u03C7\u03B5\u03C4\u03B1\u03B9 \u03B1\u03C1\u03C7\u03B5\u03AF\u03B1 \u03C4\u03CD\u03C0\u03BF\u03C5 HTML \u03BA\u03B1\u03B9 \u03C4\u03CD\u03C0\u03BF\u03C5 ZIP \u03C0\u03BF\u03C5 \u03C0\u03B5\u03C1\u03B9\u03AD\u03C7\u03BF\u03C5\u03BD html/css/\u03B5\u03B9\u03BA\u03CC\u03BD\u03B5\u03C2 \u03BA.\u03BB\u03C0. \u03C0\u03BF\u03C5 \u03B1\u03C0\u03B1\u03B9\u03C4\u03BF\u03CD\u03BD\u03C4\u03B1\u03B9
|
HTMLToPDF.help=\u0394\u03AD\u03C7\u03B5\u03C4\u03B1\u03B9 \u03B1\u03C1\u03C7\u03B5\u03AF\u03B1 \u03C4\u03CD\u03C0\u03BF\u03C5 HTML \u03BA\u03B1\u03B9 \u03C4\u03CD\u03C0\u03BF\u03C5 ZIP \u03C0\u03BF\u03C5 \u03C0\u03B5\u03C1\u03B9\u03AD\u03C7\u03BF\u03C5\u03BD html/css/\u03B5\u03B9\u03BA\u03CC\u03BD\u03B5\u03C2 \u03BA.\u03BB\u03C0. \u03C0\u03BF\u03C5 \u03B1\u03C0\u03B1\u03B9\u03C4\u03BF\u03CD\u03BD\u03C4\u03B1\u03B9
|
||||||
HTMLToPDF.submit=\u039C\u03B5\u03C4\u03B1\u03C4\u03C1\u03BF\u03C0\u03AE
|
HTMLToPDF.submit=\u039C\u03B5\u03C4\u03B1\u03C4\u03C1\u03BF\u03C0\u03AE
|
||||||
HTMLToPDF.credit=\u03A7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03B5\u03AF WeasyPrint
|
HTMLToPDF.credit=\u03A7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03B5\u03AF WeasyPrint
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=\u0391\u03C0\u03BF\u03BB\u03CD\u03BC\u03B1\u03BD\u03C3\u03B7 PDF
|
sanitizePDF.title=\u0391\u03C0\u03BF\u03BB\u03CD\u03BC\u03B1\u03BD\u03C3\u03B7 PDF
|
||||||
sanitizePDF.header=\u0391\u03C0\u03BF\u03BB\u03CD\u03BC\u03B1\u03BD\u03C3\u03B7 \u03B5\u03BD\u03CC\u03C2 PDF \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5
|
sanitizePDF.header=\u0391\u03C0\u03BF\u03BB\u03CD\u03BC\u03B1\u03BD\u03C3\u03B7 \u03B5\u03BD\u03CC\u03C2 PDF \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5
|
||||||
|
@ -44,7 +44,8 @@ blue=Blue
|
|||||||
custom=Custom...
|
custom=Custom...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=Credentials changed!
|
changedCredsMessage=Credentials changed!
|
||||||
notAuthenticatedMessage=User not authenticated.
|
notAuthenticatedMessage=User not authenticated.
|
||||||
userNotFoundMessage=User not found.
|
userNotFoundMessage=User not found.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ 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
|
split-by-sections.tags=Section Split, Divide, Customize
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML To PDF
|
|||||||
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
HTMLToPDF.submit=Convert
|
HTMLToPDF.submit=Convert
|
||||||
HTMLToPDF.credit=Uses WeasyPrint
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=Sanitize PDF
|
sanitizePDF.title=Sanitize PDF
|
||||||
sanitizePDF.header=Sanitize a PDF file
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
@ -44,7 +44,8 @@ blue=Blue
|
|||||||
custom=Custom...
|
custom=Custom...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=Credentials changed!
|
changedCredsMessage=Credentials changed!
|
||||||
notAuthenticatedMessage=User not authenticated.
|
notAuthenticatedMessage=User not authenticated.
|
||||||
userNotFoundMessage=User not found.
|
userNotFoundMessage=User not found.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ 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
|
split-by-sections.tags=Section Split, Divide, Customize
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML To PDF
|
|||||||
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
HTMLToPDF.help=Accepts HTML files and ZIPs containing html/css/images etc required
|
||||||
HTMLToPDF.submit=Convert
|
HTMLToPDF.submit=Convert
|
||||||
HTMLToPDF.credit=Uses WeasyPrint
|
HTMLToPDF.credit=Uses WeasyPrint
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=Sanitize PDF
|
sanitizePDF.title=Sanitize PDF
|
||||||
sanitizePDF.header=Sanitize a PDF file
|
sanitizePDF.header=Sanitize a PDF file
|
||||||
|
@ -42,9 +42,10 @@ red=Rojo
|
|||||||
green=Verde
|
green=Verde
|
||||||
blue=Azul
|
blue=Azul
|
||||||
custom=Personalizado...
|
custom=Personalizado...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Tarea en progreso, puede no funcionar o ralentizarse; ¡por favor, informe de cualquier problema!
|
||||||
poweredBy=Powered by
|
poweredBy=Desarrollado por
|
||||||
|
yes=Sí
|
||||||
|
no=No
|
||||||
changedCredsMessage=Se cambiaron las credenciales!
|
changedCredsMessage=Se cambiaron las credenciales!
|
||||||
notAuthenticatedMessage=Usuario no autentificado.
|
notAuthenticatedMessage=Usuario no autentificado.
|
||||||
userNotFoundMessage=Usuario no encontrado.
|
userNotFoundMessage=Usuario no encontrado.
|
||||||
@ -55,23 +56,24 @@ usernameExistsMessage=El nuevo nombre de usuario está en uso.
|
|||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
###############
|
###############
|
||||||
pipeline.header=Pipeline Menu (Alpha)
|
pipeline.header=Menu Pipeline (Alfa)
|
||||||
pipeline.uploadButton=Upload Custom
|
pipeline.uploadButton=Cargar personalización
|
||||||
pipeline.configureButton=Configure
|
pipeline.configureButton=Configurar
|
||||||
pipeline.defaultOption=Custom
|
pipeline.defaultOption=Personalizar
|
||||||
pipeline.submitButton=Submit
|
pipeline.submitButton=Enviar
|
||||||
|
|
||||||
######################
|
######################
|
||||||
# Pipeline Options #
|
# Pipeline Options #
|
||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Configuración Pipeline
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Nombre del Pipeline
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Guardar configuración de la oiperación
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Introduzca aquí el nombre del pipeline
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.selectOperation=Seleccione la operación
|
||||||
|
pipelineOptions.addOperationButton=Añadir operación
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Descargar
|
||||||
pipelineOptions.validateButton=Validate
|
pipelineOptions.validateButton=Validar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -384,6 +386,11 @@ home.split-by-sections.title=Dividir PDF por Secciones
|
|||||||
home.split-by-sections.desc=Dividir cada página de un PDF en secciones verticales y horizontales más pequeñas
|
home.split-by-sections.desc=Dividir cada página de un PDF en secciones verticales y horizontales más pequeñas
|
||||||
split-by-sections.tags=Dividir sección, Dividir, Personalizar
|
split-by-sections.tags=Dividir sección, Dividir, Personalizar
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML a PDF
|
|||||||
HTMLToPDF.help=Acepta archivos HTML y ZIPs conteniendo los html/css/imágenes, etc, requeridas
|
HTMLToPDF.help=Acepta archivos HTML y ZIPs conteniendo los html/css/imágenes, etc, requeridas
|
||||||
HTMLToPDF.submit=Convertir
|
HTMLToPDF.submit=Convertir
|
||||||
HTMLToPDF.credit=Utiliza WeasyPrint
|
HTMLToPDF.credit=Utiliza WeasyPrint
|
||||||
|
HTMLToPDF.zoom=Nivel de zoom para mostrar la página web.
|
||||||
|
HTMLToPDF.pageWidth=Ancho de la página en centímetros. (Dejar en blanco por defecto)
|
||||||
|
HTMLToPDF.pageHeight=Alto de la página en centímetros. (Dejar en blanco por defecto)
|
||||||
|
HTMLToPDF.marginTop=Margen superior de la página en milímetros. (Dejar en blanco por defecto)
|
||||||
|
HTMLToPDF.marginBottom=Margen inferior de la página en milímetros. (Dejar en blanco por defecto)
|
||||||
|
HTMLToPDF.marginLeft=Margen izquierdo de la página en milímetros. (Dejar en blanco por defecto)
|
||||||
|
HTMLToPDF.marginRight=Margen derecho de la página en milímetros. (Dejar en blanco por defecto)
|
||||||
|
HTMLToPDF.printBackground=Renderizar el fondo de las páginas web.
|
||||||
|
HTMLToPDF.defaultHeader=Habilitar encabezado predeterminado (Nombre y número de página)
|
||||||
|
HTMLToPDF.cssMediaType=Cambiar el tipo de medio CSS de la página.
|
||||||
|
HTMLToPDF.none=Ninguno
|
||||||
|
HTMLToPDF.print=Imprimir
|
||||||
|
HTMLToPDF.screen=Pantalla
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Sellar PDF
|
||||||
|
AddStampRequest.title=Sellar PDF
|
||||||
|
AddStampRequest.stampType=Tipo de sello
|
||||||
|
AddStampRequest.stampText=Texto del sello
|
||||||
|
AddStampRequest.stampImage=Imagen de sello
|
||||||
|
AddStampRequest.alphabet=Alfabeto
|
||||||
|
AddStampRequest.fontSize=Tamaño de fuente/imagen
|
||||||
|
AddStampRequest.rotation=Rotación
|
||||||
|
AddStampRequest.opacity=Opacidad
|
||||||
|
AddStampRequest.position=Posición
|
||||||
|
AddStampRequest.overrideX=Forzar coordenada X
|
||||||
|
AddStampRequest.overrideY=Forzar coordenada Y
|
||||||
|
AddStampRequest.customMargin=Personalizar margen
|
||||||
|
AddStampRequest.customColor=Personalizar color de texto
|
||||||
|
AddStampRequest.submit=Enviar
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=Desinfectar archivo PDF
|
sanitizePDF.title=Desinfectar archivo PDF
|
||||||
sanitizePDF.header=Desinfectar un archivo PDF
|
sanitizePDF.header=Desinfectar un archivo PDF
|
||||||
@ -547,11 +584,11 @@ scalePages.submit=Entregar
|
|||||||
certSign.title=Firma con certificado
|
certSign.title=Firma con certificado
|
||||||
certSign.header=Firmar un PDF con su certificado (en desarrollo)
|
certSign.header=Firmar un PDF con su certificado (en desarrollo)
|
||||||
certSign.selectPDF=Seleccione un archivo PDF para firmar:
|
certSign.selectPDF=Seleccione un archivo PDF para firmar:
|
||||||
certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below.
|
certSign.jksNote=Nota: si el tipo de certificado no está enla lista de abajo, por favor conviértalo a un archivo almacén de claves de Java Java KeyStore (.jks) utilizando la herramienta línea de comandos. Posteriormente, seleccione en el listado de abajo la opción archivo .jks.
|
||||||
certSign.selectKey=Seleccione su archivo de clave privada (formato PKCS#8, podría ser .pem o .der):
|
certSign.selectKey=Seleccione su archivo de clave privada (formato PKCS#8, podría ser .pem o .der):
|
||||||
certSign.selectCert=Seleccione su archivo de certificado (formato X.509, podría ser .pem o .der):
|
certSign.selectCert=Seleccione su archivo de certificado (formato X.509, podría ser .pem o .der):
|
||||||
certSign.selectP12=Seleccione su archivo de almacén de claves PKCS#12 (.p12 o .pfx) (Opcional, si se proporciona, debe contener su clave privada y certificado):
|
certSign.selectP12=Seleccione su archivo de almacén de claves PKCS#12 (.p12 o .pfx) (Opcional, si se proporciona, debe contener su clave privada y certificado):
|
||||||
certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore):
|
certSign.selectJKS=Seleccione su archivo de almacén de claves Java KeyStore (.jks or .keystore):
|
||||||
certSign.certType=Tipo de certificado
|
certSign.certType=Tipo de certificado
|
||||||
certSign.password=Introduzca su almacén de claves o contraseña de clave privada (si corresponde):
|
certSign.password=Introduzca su almacén de claves o contraseña de clave privada (si corresponde):
|
||||||
certSign.showSig=Mostrar firma
|
certSign.showSig=Mostrar firma
|
||||||
@ -924,11 +961,11 @@ split-by-sections.submit=Dividir PDF
|
|||||||
|
|
||||||
|
|
||||||
#licenses
|
#licenses
|
||||||
licenses.nav=Licenses
|
licenses.nav=Licencias
|
||||||
licenses.title=3rd Party Licenses
|
licenses.title=Licencias de terceros
|
||||||
licenses.header=3rd Party Licenses
|
licenses.header=Licencias de terceros
|
||||||
licenses.module=Module
|
licenses.module=Módulo
|
||||||
licenses.version=Version
|
licenses.version=Versión
|
||||||
licenses.license=License
|
licenses.license=Licencia
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,8 @@ blue=Urdina
|
|||||||
custom=Pertsonalizatu...
|
custom=Pertsonalizatu...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=Credentials changed!
|
changedCredsMessage=Credentials changed!
|
||||||
notAuthenticatedMessage=User not authenticated.
|
notAuthenticatedMessage=User not authenticated.
|
||||||
userNotFoundMessage=User not found.
|
userNotFoundMessage=User not found.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ 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
|
split-by-sections.tags=Section Split, Divide, Customize
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML bat PDF-ra
|
|||||||
HTMLToPDF.help=Html/css/images etab dituen HTML eta Zip fitxategiak onartzen ditu
|
HTMLToPDF.help=Html/css/images etab dituen HTML eta Zip fitxategiak onartzen ditu
|
||||||
HTMLToPDF.submit=Bihurtu
|
HTMLToPDF.submit=Bihurtu
|
||||||
HTMLToPDF.credit=WeasyPrint darabil
|
HTMLToPDF.credit=WeasyPrint darabil
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=PDF-a desinfektatu
|
sanitizePDF.title=PDF-a desinfektatu
|
||||||
sanitizePDF.header=PDF fitxategi bat desinfektatu
|
sanitizePDF.header=PDF fitxategi bat desinfektatu
|
||||||
|
@ -44,7 +44,8 @@ blue=Bleu
|
|||||||
custom=Personnalisé\u2026
|
custom=Personnalisé\u2026
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=Les identifiants ont été mis à jour\u00a0!
|
changedCredsMessage=Les identifiants ont été mis à jour\u00a0!
|
||||||
notAuthenticatedMessage=Utilisateur non authentifié.
|
notAuthenticatedMessage=Utilisateur non authentifié.
|
||||||
userNotFoundMessage=Utilisateur non trouvé.
|
userNotFoundMessage=Utilisateur non trouvé.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ 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
|
split-by-sections.tags=Section Split, Divide, Customize
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML en PDF
|
|||||||
HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis).
|
HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis).
|
||||||
HTMLToPDF.submit=Convertir
|
HTMLToPDF.submit=Convertir
|
||||||
HTMLToPDF.credit=Utilise WeasyPrint.
|
HTMLToPDF.credit=Utilise WeasyPrint.
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=Assainir
|
sanitizePDF.title=Assainir
|
||||||
sanitizePDF.header=Assainir
|
sanitizePDF.header=Assainir
|
||||||
|
@ -44,7 +44,8 @@ blue=नीला
|
|||||||
custom=कस्टम...
|
custom=कस्टम...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=क्रेडेंशियल्स बदल दी गईं!
|
changedCredsMessage=क्रेडेंशियल्स बदल दी गईं!
|
||||||
notAuthenticatedMessage=उपयोगकर्ता प्रमाणित नहीं है।
|
notAuthenticatedMessage=उपयोगकर्ता प्रमाणित नहीं है।
|
||||||
userNotFoundMessage=उपयोगकर्ता नहीं मिला।
|
userNotFoundMessage=उपयोगकर्ता नहीं मिला।
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ home.split-by-sections.title=खंडों से पीडीएफ़ वि
|
|||||||
home.split-by-sections.desc=पीडीएफ़ के प्रत्येक पृष्ठ को छोटे से छोटे क्षैतिज और ऊर्ध्वाधर खंडों में विभाजित करें
|
home.split-by-sections.desc=पीडीएफ़ के प्रत्येक पृष्ठ को छोटे से छोटे क्षैतिज और ऊर्ध्वाधर खंडों में विभाजित करें
|
||||||
split-by-sections.tags=खंड विभाजन, विभाजित करें, अनुकूलित
|
split-by-sections.tags=खंड विभाजन, विभाजित करें, अनुकूलित
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML से पीडीएफ़
|
|||||||
HTMLToPDF.help=HTML फ़ाइलों और html/css/images आदि को आत्मसात करने वाले ZIPs को स्वीकार करता है
|
HTMLToPDF.help=HTML फ़ाइलों और html/css/images आदि को आत्मसात करने वाले ZIPs को स्वीकार करता है
|
||||||
HTMLToPDF.submit=रूपांतरित करें
|
HTMLToPDF.submit=रूपांतरित करें
|
||||||
HTMLToPDF.credit=WeasyPrint का प्रयोग होता है
|
HTMLToPDF.credit=WeasyPrint का प्रयोग होता है
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=पीडीएफ़ को सफाई करें
|
sanitizePDF.title=पीडीएफ़ को सफाई करें
|
||||||
sanitizePDF.header=एक पीडीएफ़ फ़ाइल को सफाई करें
|
sanitizePDF.header=एक पीडीएफ़ फ़ाइल को सफाई करें
|
||||||
|
@ -44,7 +44,8 @@ blue=Kék
|
|||||||
custom=Egyedi...
|
custom=Egyedi...
|
||||||
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
|
||||||
poweredBy=Powered by
|
poweredBy=Powered by
|
||||||
|
yes=Yes
|
||||||
|
no=No
|
||||||
changedCredsMessage=A hitelek megváltoztak!
|
changedCredsMessage=A hitelek megváltoztak!
|
||||||
notAuthenticatedMessage=Felhasználó nincs hitelesítve.
|
notAuthenticatedMessage=Felhasználó nincs hitelesítve.
|
||||||
userNotFoundMessage=A felhasználó nem található.
|
userNotFoundMessage=A felhasználó nem található.
|
||||||
@ -66,8 +67,9 @@ pipeline.submitButton=Submit
|
|||||||
######################
|
######################
|
||||||
pipelineOptions.header=Pipeline Configuration
|
pipelineOptions.header=Pipeline Configuration
|
||||||
pipelineOptions.pipelineNameLabel=Pipeline Name
|
pipelineOptions.pipelineNameLabel=Pipeline Name
|
||||||
pipelineOptions.saveSettings=Save Settings
|
pipelineOptions.saveSettings=Save Operation Settings
|
||||||
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
|
||||||
|
pipelineOptions.selectOperation=Select Operation
|
||||||
pipelineOptions.addOperationButton=Add operation
|
pipelineOptions.addOperationButton=Add operation
|
||||||
pipelineOptions.pipelineHeader=Pipeline:
|
pipelineOptions.pipelineHeader=Pipeline:
|
||||||
pipelineOptions.saveButton=Download
|
pipelineOptions.saveButton=Download
|
||||||
@ -384,6 +386,11 @@ home.split-by-sections.title=PDF Szakaszokra osztása
|
|||||||
home.split-by-sections.desc=Minden oldal felosztása kisebb vízszintes és függőleges szakaszokra
|
home.split-by-sections.desc=Minden oldal felosztása kisebb vízszintes és függőleges szakaszokra
|
||||||
split-by-sections.tags=Szakasz elosztás, felosztás, testreszabás
|
split-by-sections.tags=Szakasz elosztás, felosztás, testreszabás
|
||||||
|
|
||||||
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
@ -459,8 +466,38 @@ HTMLToPDF.header=HTML >> PDF
|
|||||||
HTMLToPDF.help=Elfogad HTML fájlokat és ZIP-fájlokat, amelyek tartalmaznak html/css/képeket stb.
|
HTMLToPDF.help=Elfogad HTML fájlokat és ZIP-fájlokat, amelyek tartalmaznak html/css/képeket stb.
|
||||||
HTMLToPDF.submit=Átalakítás
|
HTMLToPDF.submit=Átalakítás
|
||||||
HTMLToPDF.credit=WeasyPrint alkalmazása
|
HTMLToPDF.credit=WeasyPrint alkalmazása
|
||||||
|
HTMLToPDF.zoom=Zoom level for displaying the website.
|
||||||
|
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
|
||||||
|
HTMLToPDF.printBackground=Render the background of websites.
|
||||||
|
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
|
||||||
|
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
|
||||||
|
HTMLToPDF.none=None
|
||||||
|
HTMLToPDF.print=Print
|
||||||
|
HTMLToPDF.screen=Screen
|
||||||
|
|
||||||
|
|
||||||
|
#AddStampRequest
|
||||||
|
AddStampRequest.header=Stamp PDF
|
||||||
|
AddStampRequest.title=Stamp PDF
|
||||||
|
AddStampRequest.stampType=Stamp Type
|
||||||
|
AddStampRequest.stampText=Stamp Text
|
||||||
|
AddStampRequest.stampImage=Stamp Image
|
||||||
|
AddStampRequest.alphabet=Alphabet
|
||||||
|
AddStampRequest.fontSize=Font/Image Size
|
||||||
|
AddStampRequest.rotation=Rotation
|
||||||
|
AddStampRequest.opacity=Opacity
|
||||||
|
AddStampRequest.position=Position
|
||||||
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
|
AddStampRequest.customMargin=Custom Margin
|
||||||
|
AddStampRequest.customColor=Custom Text Color
|
||||||
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
#sanitizePDF
|
#sanitizePDF
|
||||||
sanitizePDF.title=PDF tisztítása
|
sanitizePDF.title=PDF tisztítása
|
||||||
sanitizePDF.header=PDF fájl megtisztítása
|
sanitizePDF.header=PDF fájl megtisztítása
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user