mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-12 17:52:13 +02:00
Merge branch 'Stirling-Tools:main' into main
This commit is contained in:
commit
cc3bff2f52
3
.github/labeler-config.yml
vendored
3
.github/labeler-config.yml
vendored
@ -72,7 +72,8 @@ Devtools:
|
|||||||
Test:
|
Test:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: 'cucumber/**/*'
|
- any-glob-to-any-file: 'cucumber/**/*'
|
||||||
- any-glob-to-any-file: 'src/test**/*'
|
- any-glob-to-any-file: 'src/test/**/*'
|
||||||
|
- any-glob-to-any-file: 'src/testing/**/*'
|
||||||
- any-glob-to-any-file: '.pre-commit-config'
|
- any-glob-to-any-file: '.pre-commit-config'
|
||||||
- any-glob-to-any-file: '.github/workflows/pre_commit.yml'
|
- any-glob-to-any-file: '.github/workflows/pre_commit.yml'
|
||||||
- any-glob-to-any-file: '.github/workflows/scorecards.yml'
|
- any-glob-to-any-file: '.github/workflows/scorecards.yml'
|
||||||
|
4
.github/workflows/swagger.yml
vendored
4
.github/workflows/swagger.yml
vendored
@ -35,6 +35,7 @@ jobs:
|
|||||||
run: ./gradlew swaggerhubUpload
|
run: ./gradlew swaggerhubUpload
|
||||||
env:
|
env:
|
||||||
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
|
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
|
||||||
|
SWAGGERHUB_USER: "Frooodle"
|
||||||
|
|
||||||
- name: Get version number
|
- name: Get version number
|
||||||
id: versionNumber
|
id: versionNumber
|
||||||
@ -42,6 +43,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set API version as published and default on SwaggerHub
|
- name: Set API version as published and default on SwaggerHub
|
||||||
run: |
|
run: |
|
||||||
curl -X PUT -H "Authorization: ${SWAGGERHUB_API_KEY}" "https://api.swaggerhub.com/apis/Frooodle/Stirling-PDF/${{ steps.versionNumber.outputs.versionNumber }}/settings/lifecycle" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"published\":true,\"default\":true}"
|
curl -X PUT -H "Authorization: ${SWAGGERHUB_API_KEY}" "https://api.swaggerhub.com/apis/${SWAGGERHUB_USER}/Stirling-PDF/${{ steps.versionNumber.outputs.versionNumber }}/settings/lifecycle" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"published\":true,\"default\":true}"
|
||||||
env:
|
env:
|
||||||
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
|
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
|
||||||
|
SWAGGERHUB_USER: "Frooodle"
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -27,6 +27,8 @@ clientWebUI/
|
|||||||
!cucumber/exampleFiles/example_html.zip
|
!cucumber/exampleFiles/example_html.zip
|
||||||
exampleYmlFiles/stirling/
|
exampleYmlFiles/stirling/
|
||||||
/testing/file_snapshots
|
/testing/file_snapshots
|
||||||
|
SwaggerDoc.json
|
||||||
|
|
||||||
# Gradle
|
# Gradle
|
||||||
.gradle
|
.gradle
|
||||||
.lock
|
.lock
|
||||||
@ -188,3 +190,7 @@ id_ed25519.pub
|
|||||||
.ipynb_checkpoints
|
.ipynb_checkpoints
|
||||||
|
|
||||||
**/jcef-bundle/
|
**/jcef-bundle/
|
||||||
|
|
||||||
|
# node_modules
|
||||||
|
node_modules/
|
||||||
|
*.mjs
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Build the application
|
# Build the application
|
||||||
FROM gradle:8.12-jdk21 AS build
|
FROM gradle:8.13-jdk21 AS build
|
||||||
|
|
||||||
COPY build.gradle .
|
COPY build.gradle .
|
||||||
COPY settings.gradle .
|
COPY settings.gradle .
|
||||||
|
12
README.md
12
README.md
@ -120,17 +120,17 @@ Stirling-PDF currently supports 39 languages!
|
|||||||
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
||||||
| Basque (Euskara) (eu_ES) |  |
|
| Basque (Euskara) (eu_ES) |  |
|
||||||
| Bulgarian (Български) (bg_BG) |  |
|
| Bulgarian (Български) (bg_BG) |  |
|
||||||
| Catalan (Català) (ca_CA) |  |
|
| Catalan (Català) (ca_CA) |  |
|
||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
| Dutch (Nederlands) (nl_NL) |  |
|
| Dutch (Nederlands) (nl_NL) |  |
|
||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
| German (Deutsch) (de_DE) |  |
|
| German (Deutsch) (de_DE) |  |
|
||||||
| Greek (Ελληνικά) (el_GR) |  |
|
| Greek (Ελληνικά) (el_GR) |  |
|
||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||||
| Irish (Gaeilge) (ga_IE) |  |
|
| Irish (Gaeilge) (ga_IE) |  |
|
||||||
@ -138,7 +138,7 @@ Stirling-PDF currently supports 39 languages!
|
|||||||
| Japanese (日本語) (ja_JP) |  |
|
| Japanese (日本語) (ja_JP) |  |
|
||||||
| Korean (한국어) (ko_KR) |  |
|
| Korean (한국어) (ko_KR) |  |
|
||||||
| Norwegian (Norsk) (no_NB) |  |
|
| Norwegian (Norsk) (no_NB) |  |
|
||||||
| Persian (فارسی) (fa_IR) |  |
|
| Persian (فارسی) (fa_IR) |  |
|
||||||
| Polish (Polski) (pl_PL) |  |
|
| Polish (Polski) (pl_PL) |  |
|
||||||
| Portuguese (Português) (pt_PT) |  |
|
| Portuguese (Português) (pt_PT) |  |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
@ -146,7 +146,7 @@ Stirling-PDF currently supports 39 languages!
|
|||||||
| Russian (Русский) (ru_RU) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Slovenian (Slovenščina) (sl_SI) |  |
|
| Slovenian (Slovenščina) (sl_SI) |  |
|
||||||
| Spanish (Español) (es_ES) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
| Swedish (Svenska) (sv_SE) |  |
|
| Swedish (Svenska) (sv_SE) |  |
|
||||||
@ -154,7 +154,7 @@ Stirling-PDF currently supports 39 languages!
|
|||||||
| Tibetan (བོད་ཡིག་) (zh_BO) |  |
|
| Tibetan (བོད་ཡིག་) (zh_BO) |  |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||||
|
|
||||||
|
|
||||||
|
33
build.gradle
33
build.gradle
@ -2,7 +2,7 @@ plugins {
|
|||||||
id "java"
|
id "java"
|
||||||
id "org.springframework.boot" version "3.4.3"
|
id "org.springframework.boot" version "3.4.3"
|
||||||
id "io.spring.dependency-management" version "1.1.7"
|
id "io.spring.dependency-management" version "1.1.7"
|
||||||
id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
|
id "org.springdoc.openapi-gradle-plugin" version "1.9.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.6"
|
id "edu.sc.seis.launch4j" version "3.0.6"
|
||||||
id "com.diffplug.spotless" version "7.0.2"
|
id "com.diffplug.spotless" version "7.0.2"
|
||||||
@ -25,7 +25,7 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "stirling.software"
|
group = "stirling.software"
|
||||||
version = "0.44.1"
|
version = "0.44.2"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
// 17 is lowest but we support and recommend 21
|
// 17 is lowest but we support and recommend 21
|
||||||
@ -98,6 +98,7 @@ openApi {
|
|||||||
apiDocsUrl = "http://localhost:8080/v1/api-docs"
|
apiDocsUrl = "http://localhost:8080/v1/api-docs"
|
||||||
outputDir = file("$projectDir")
|
outputDir = file("$projectDir")
|
||||||
outputFileName = "SwaggerDoc.json"
|
outputFileName = "SwaggerDoc.json"
|
||||||
|
waitTimeInSeconds = 60 // Increase the wait time to 60 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
//0.11.5 to 2024.11.5
|
//0.11.5 to 2024.11.5
|
||||||
@ -256,7 +257,7 @@ launch4j {
|
|||||||
|
|
||||||
spotless {
|
spotless {
|
||||||
java {
|
java {
|
||||||
target project.fileTree('src/main/java')
|
target project.fileTree('src').include('**/*.java')
|
||||||
|
|
||||||
googleJavaFormat("1.25.2").aosp().reorderImports(false)
|
googleJavaFormat("1.25.2").aosp().reorderImports(false)
|
||||||
|
|
||||||
@ -284,11 +285,15 @@ sonar {
|
|||||||
// }
|
// }
|
||||||
tasks.wrapper {
|
tasks.wrapper {
|
||||||
gradleVersion = "8.12"
|
gradleVersion = "8.12"
|
||||||
|
distributionType = Wrapper.DistributionType.ALL
|
||||||
}
|
}
|
||||||
//tasks.withType(JavaCompile) {
|
//tasks.withType(JavaCompile) {
|
||||||
// options.compilerArgs << "-Xlint:deprecation"
|
// options.compilerArgs << "-Xlint:deprecation"
|
||||||
//}
|
//}
|
||||||
configurations.all {
|
configurations.all {
|
||||||
|
// Remove all commons-logging dependencies so that only spring-jcl is used
|
||||||
|
exclude group: 'commons-logging', module: 'commons-logging'
|
||||||
|
// Exclude Tomcat
|
||||||
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -381,19 +386,13 @@ dependencies {
|
|||||||
//general PDF
|
//general PDF
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/com.opencsv/opencsv
|
// https://mvnrepository.com/artifact/com.opencsv/opencsv
|
||||||
implementation ("com.opencsv:opencsv:5.10") {
|
implementation ("com.opencsv:opencsv:5.10")
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
|
||||||
}
|
|
||||||
|
|
||||||
implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion") {
|
implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion")
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
|
||||||
}
|
|
||||||
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
|
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
|
||||||
|
|
||||||
|
|
||||||
implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion") {
|
implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion")
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/technology.tabula/tabula
|
// https://mvnrepository.com/artifact/technology.tabula/tabula
|
||||||
implementation ('technology.tabula:tabula:1.0.5') {
|
implementation ('technology.tabula:tabula:1.0.5') {
|
||||||
@ -407,7 +406,7 @@ dependencies {
|
|||||||
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
|
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
|
||||||
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
|
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
|
||||||
implementation "io.micrometer:micrometer-core:1.14.4"
|
implementation "io.micrometer:micrometer-core:1.14.5"
|
||||||
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
|
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
|
||||||
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
||||||
implementation "org.commonmark:commonmark:0.24.0"
|
implementation "org.commonmark:commonmark:0.24.0"
|
||||||
@ -443,9 +442,9 @@ task writeVersion {
|
|||||||
swaggerhubUpload {
|
swaggerhubUpload {
|
||||||
// dependsOn = generateOpenApiDocs // Depends on your task generating Swagger docs
|
// dependsOn = generateOpenApiDocs // Depends on your task generating Swagger docs
|
||||||
api = "Stirling-PDF" // The name of your API on SwaggerHub
|
api = "Stirling-PDF" // The name of your API on SwaggerHub
|
||||||
owner = "Frooodle" // Your SwaggerHub username (or organization name)
|
owner = "${System.getenv().getOrDefault('SWAGGERHUB_USER', 'Frooodle')}" // Your SwaggerHub username (or organization name)
|
||||||
version = project.version // The version of your API
|
version = project.version // The version of your API
|
||||||
inputFile = "./SwaggerDoc.json" // The path to your Swagger docs
|
inputFile = file("SwaggerDoc.json") // The path to your Swagger docs
|
||||||
token = "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable
|
token = "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable
|
||||||
oas = "3.0.0" // The version of the OpenAPI Specification you"re using
|
oas = "3.0.0" // The version of the OpenAPI Specification you"re using
|
||||||
}
|
}
|
||||||
@ -473,3 +472,7 @@ task printMacVersion {
|
|||||||
println getMacVersion(project.version.toString())
|
println getMacVersion(project.version.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.named('generateOpenApiDocs') {
|
||||||
|
doNotTrackState("Tracking state is not supported for this task")
|
||||||
|
}
|
||||||
|
@ -18,17 +18,17 @@ 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.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/analysis")
|
@RequestMapping("/api/v1/analysis")
|
||||||
@Tag(name = "Analysis", description = "Analysis APIs")
|
@Tag(name = "Analysis", description = "Analysis APIs")
|
||||||
public class AnalysisController {
|
public class AnalysisController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public AnalysisController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public AnalysisController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,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.CropPdfForm;
|
import stirling.software.SPDF.model.api.general.CropPdfForm;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -29,10 +29,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class CropController {
|
public class CropController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public CropController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public CropController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,8 @@ public class CropController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Crops a PDF document",
|
summary = "Crops a PDF document",
|
||||||
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 = pdfDocumentFactory.load(form);
|
PDDocument sourceDocument = pdfDocumentFactory.load(form);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
|
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -43,10 +43,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class MergeController {
|
public class MergeController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public MergeController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public MergeController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,9 @@ public class MergeController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Merge multiple PDF files into one",
|
summary = "Merge multiple PDF files into one",
|
||||||
description =
|
description =
|
||||||
"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<>(); // List of temporary files to delete
|
List<File> filesToDelete = new ArrayList<>(); // List of temporary files to delete
|
||||||
|
@ -24,7 +24,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.MergeMultiplePagesRequest;
|
import stirling.software.SPDF.model.api.general.MergeMultiplePagesRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -32,10 +32,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class MultiPageLayoutController {
|
public class MultiPageLayoutController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public MultiPageLayoutController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public MultiPageLayoutController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,8 @@ public class MultiPageLayoutController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Merge multiple pages of a PDF document into a single page",
|
summary = "Merge multiple pages of a PDF document into a single page",
|
||||||
description =
|
description =
|
||||||
"This operation takes an input PDF file and the number of pages to merge into a single sheet in the output PDF file. Input:PDF Output:PDF Type:SISO")
|
"This operation takes an input PDF file and the number of pages to merge into a"
|
||||||
|
+ " single sheet in the output PDF file. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> mergeMultiplePagesIntoOne(
|
public ResponseEntity<byte[]> mergeMultiplePagesIntoOne(
|
||||||
@ModelAttribute MergeMultiplePagesRequest request) throws IOException {
|
@ModelAttribute MergeMultiplePagesRequest request) throws IOException {
|
||||||
|
|
||||||
|
@ -15,7 +15,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.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.service.PdfImageRemovalService;
|
import stirling.software.SPDF.service.PdfImageRemovalService;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ public class PdfImageRemovalController {
|
|||||||
// Service for removing images from PDFs
|
// Service for removing images from PDFs
|
||||||
private final PdfImageRemovalService pdfImageRemovalService;
|
private final PdfImageRemovalService pdfImageRemovalService;
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for dependency injection of PdfImageRemovalService.
|
* Constructor for dependency injection of PdfImageRemovalService.
|
||||||
@ -41,7 +41,7 @@ public class PdfImageRemovalController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
public PdfImageRemovalController(
|
public PdfImageRemovalController(
|
||||||
PdfImageRemovalService pdfImageRemovalService,
|
PdfImageRemovalService pdfImageRemovalService,
|
||||||
CustomPDDocumentFactory pdfDocumentFactory) {
|
CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfImageRemovalService = pdfImageRemovalService;
|
this.pdfImageRemovalService = pdfImageRemovalService;
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
@ -61,7 +61,8 @@ public class PdfImageRemovalController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove images from file to reduce the file size.",
|
summary = "Remove images from file to reduce the file size.",
|
||||||
description =
|
description =
|
||||||
"This endpoint remove images from file to reduce the file size.Input:PDF Output:PDF Type:MISO")
|
"This endpoint remove images from file to reduce the file size.Input:PDF"
|
||||||
|
+ " Output:PDF Type:MISO")
|
||||||
public ResponseEntity<byte[]> removeImages(@ModelAttribute PDFFile file) throws IOException {
|
public ResponseEntity<byte[]> removeImages(@ModelAttribute PDFFile file) throws IOException {
|
||||||
// Load the PDF document
|
// Load the PDF document
|
||||||
PDDocument document = pdfDocumentFactory.load(file);
|
PDDocument document = pdfDocumentFactory.load(file);
|
||||||
|
@ -26,7 +26,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.OverlayPdfsRequest;
|
import stirling.software.SPDF.model.api.general.OverlayPdfsRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -35,10 +35,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class PdfOverlayController {
|
public class PdfOverlayController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public PdfOverlayController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public PdfOverlayController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,8 @@ public class PdfOverlayController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Overlay PDF files in various modes",
|
summary = "Overlay PDF files in various modes",
|
||||||
description =
|
description =
|
||||||
"Overlay PDF files onto a base PDF with different modes: Sequential, Interleaved, or Fixed Repeat. Input:PDF Output:PDF Type:MIMO")
|
"Overlay PDF files onto a base PDF with different modes: Sequential,"
|
||||||
|
+ " Interleaved, or Fixed Repeat. Input:PDF Output:PDF Type:MIMO")
|
||||||
public ResponseEntity<byte[]> overlayPdfs(@ModelAttribute OverlayPdfsRequest request)
|
public ResponseEntity<byte[]> overlayPdfs(@ModelAttribute OverlayPdfsRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile baseFile = request.getFileInput();
|
MultipartFile baseFile = request.getFileInput();
|
||||||
|
@ -24,7 +24,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.model.SortTypes;
|
import stirling.software.SPDF.model.SortTypes;
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||||
import stirling.software.SPDF.model.api.general.RearrangePagesRequest;
|
import stirling.software.SPDF.model.api.general.RearrangePagesRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -34,10 +34,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class RearrangePagesPDFController {
|
public class RearrangePagesPDFController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public RearrangePagesPDFController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public RearrangePagesPDFController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,9 @@ public class RearrangePagesPDFController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove pages from a PDF file",
|
summary = "Remove pages from a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint removes specified pages from a given PDF file. Users can provide a comma-separated list of page numbers or ranges to delete. Input:PDF Output:PDF Type:SISO")
|
"This endpoint removes specified pages from a given PDF file. Users can provide"
|
||||||
|
+ " a comma-separated list of page numbers or ranges to delete. Input:PDF"
|
||||||
|
+ " Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> deletePages(@ModelAttribute PDFWithPageNums request)
|
public ResponseEntity<byte[]> deletePages(@ModelAttribute PDFWithPageNums request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
@ -242,7 +244,10 @@ public class RearrangePagesPDFController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Rearrange pages in a PDF file",
|
summary = "Rearrange pages in a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint rearranges pages in a given PDF file based on the specified page order or custom mode. Users can provide a page order as a comma-separated list of page numbers or page ranges, or a custom mode. Input:PDF Output:PDF")
|
"This endpoint rearranges pages in a given PDF file based on the specified page"
|
||||||
|
+ " order or custom mode. Users can provide a page order as a"
|
||||||
|
+ " comma-separated list of page numbers or page ranges, or a custom mode."
|
||||||
|
+ " Input:PDF Output:PDF")
|
||||||
public ResponseEntity<byte[]> rearrangePages(@ModelAttribute RearrangePagesRequest request)
|
public ResponseEntity<byte[]> rearrangePages(@ModelAttribute RearrangePagesRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile pdfFile = request.getFileInput();
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
|
@ -18,7 +18,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.RotatePDFRequest;
|
import stirling.software.SPDF.model.api.general.RotatePDFRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -26,10 +26,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class RotationController {
|
public class RotationController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public RotationController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public RotationController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,11 +37,18 @@ public class RotationController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Rotate a PDF file",
|
summary = "Rotate a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint rotates a given PDF file by a specified angle. The angle must be a multiple of 90. Input:PDF Output:PDF Type:SISO")
|
"This endpoint rotates a given PDF file by a specified angle. The angle must be"
|
||||||
|
+ " a multiple of 90. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> rotatePDF(@ModelAttribute RotatePDFRequest request)
|
public ResponseEntity<byte[]> rotatePDF(@ModelAttribute RotatePDFRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile pdfFile = request.getFileInput();
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
Integer angle = request.getAngle();
|
Integer angle = request.getAngle();
|
||||||
|
|
||||||
|
// Validate the angle is a multiple of 90
|
||||||
|
if (angle % 90 != 0) {
|
||||||
|
throw new IllegalArgumentException("Angle must be a multiple of 90");
|
||||||
|
}
|
||||||
|
|
||||||
// Load the PDF document
|
// Load the PDF document
|
||||||
PDDocument document = pdfDocumentFactory.load(request);
|
PDDocument document = pdfDocumentFactory.load(request);
|
||||||
|
|
||||||
|
@ -25,7 +25,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.ScalePagesRequest;
|
import stirling.software.SPDF.model.api.general.ScalePagesRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -33,10 +33,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class ScalePagesController {
|
public class ScalePagesController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ScalePagesController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public ScalePagesController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,8 @@ public class ScalePagesController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Change the size of a PDF page/document",
|
summary = "Change the size of a PDF page/document",
|
||||||
description =
|
description =
|
||||||
"This operation takes an input PDF file and the size to scale the pages to in the output PDF file. Input:PDF Output:PDF Type:SISO")
|
"This operation takes an input PDF file and the size to scale the pages to in"
|
||||||
|
+ " the output PDF file. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> scalePages(@ModelAttribute ScalePagesRequest request)
|
public ResponseEntity<byte[]> scalePages(@ModelAttribute ScalePagesRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
@ -123,7 +124,8 @@ public class ScalePagesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Invalid PDRectangle. It must be one of the following: A0, A1, A2, A3, A4, A5, A6, LETTER, LEGAL, KEEP");
|
"Invalid PDRectangle. It must be one of the following: A0, A1, A2, A3, A4, A5, A6,"
|
||||||
|
+ " LETTER, LEGAL, KEEP");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, PDRectangle> getSizeMap() {
|
private Map<String, PDRectangle> getSizeMap() {
|
||||||
|
@ -28,7 +28,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -37,10 +37,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class SplitPDFController {
|
public class SplitPDFController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SplitPDFController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public SplitPDFController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,10 @@ public class SplitPDFController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Split a PDF file into separate documents",
|
summary = "Split a PDF file into separate documents",
|
||||||
description =
|
description =
|
||||||
"This endpoint splits a given PDF file into separate documents based on the specified page numbers or ranges. Users can specify pages using individual numbers, ranges, or 'all' for every page. Input:PDF Output:PDF Type:SIMO")
|
"This endpoint splits a given PDF file into separate documents based on the"
|
||||||
|
+ " specified page numbers or ranges. Users can specify pages using"
|
||||||
|
+ " individual numbers, ranges, or 'all' for every page. Input:PDF"
|
||||||
|
+ " Output:PDF Type:SIMO")
|
||||||
public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
|
public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.PdfMetadata;
|
import stirling.software.SPDF.model.PdfMetadata;
|
||||||
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
|
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.service.PdfMetadataService;
|
import stirling.software.SPDF.service.PdfMetadataService;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -45,11 +45,11 @@ public class SplitPdfByChaptersController {
|
|||||||
|
|
||||||
private final PdfMetadataService pdfMetadataService;
|
private final PdfMetadataService pdfMetadataService;
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SplitPdfByChaptersController(
|
public SplitPdfByChaptersController(
|
||||||
PdfMetadataService pdfMetadataService, CustomPDDocumentFactory pdfDocumentFactory) {
|
PdfMetadataService pdfMetadataService, CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfMetadataService = pdfMetadataService;
|
this.pdfMetadataService = pdfMetadataService;
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,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.SplitPdfBySectionsRequest;
|
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -39,10 +39,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class SplitPdfBySectionsController {
|
public class SplitPdfBySectionsController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SplitPdfBySectionsController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public SplitPdfBySectionsController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,9 @@ public class SplitPdfBySectionsController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Split PDF pages into smaller sections",
|
summary = "Split PDF pages into smaller sections",
|
||||||
description =
|
description =
|
||||||
"Split each page of a PDF into smaller sections based on the user's choice (halves, thirds, quarters, etc.), both vertically and horizontally. Input:PDF Output:ZIP-PDF Type:SISO")
|
"Split each page of a PDF into smaller sections based on the user's choice"
|
||||||
|
+ " (halves, thirds, quarters, etc.), both vertically and horizontally."
|
||||||
|
+ " Input:PDF Output:ZIP-PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> splitPdf(@ModelAttribute SplitPdfBySectionsRequest request)
|
public ResponseEntity<byte[]> splitPdf(@ModelAttribute SplitPdfBySectionsRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
||||||
|
@ -25,7 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
|
import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -35,22 +35,25 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class SplitPdfBySizeController {
|
public class SplitPdfBySizeController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SplitPdfBySizeController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public SplitPdfBySizeController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
log.info(
|
log.info(
|
||||||
"SplitPdfBySizeController initialized with pdfDocumentFactory: {}",
|
"SplitPdfBySizeController initialized with pdfDocumentFactory: {}",
|
||||||
pdfDocumentFactory);
|
pdfDocumentFactory.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
|
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Auto split PDF pages into separate documents based on size or count",
|
summary = "Auto split PDF pages into separate documents based on size or count",
|
||||||
description =
|
description =
|
||||||
"split PDF into multiple paged documents based on size/count, ie if 20 pages and split into 5, it does 5 documents each 4 pages\r\n"
|
"split PDF into multiple paged documents based on size/count, ie if 20 pages"
|
||||||
+ " if 10MB and each page is 1MB and you enter 2MB then 5 docs each 2MB (rounded so that it accepts 1.9MB but not 2.1MB) Input:PDF Output:ZIP-PDF Type:SISO")
|
+ " and split into 5, it does 5 documents each 4 pages\r\n"
|
||||||
|
+ " if 10MB and each page is 1MB and you enter 2MB then 5 docs each 2MB"
|
||||||
|
+ " (rounded so that it accepts 1.9MB but not 2.1MB) Input:PDF"
|
||||||
|
+ " Output:ZIP-PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> autoSplitPdf(@ModelAttribute SplitPdfBySizeOrCountRequest request)
|
public ResponseEntity<byte[]> autoSplitPdf(@ModelAttribute SplitPdfBySizeOrCountRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
|
@ -21,7 +21,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.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -29,10 +29,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class ToSinglePageController {
|
public class ToSinglePageController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ToSinglePageController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public ToSinglePageController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,10 @@ public class ToSinglePageController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a multi-page PDF into a single long page PDF",
|
summary = "Convert a multi-page PDF into a single long page PDF",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a multi-page PDF document into a single paged PDF document. The width of the single page will be same as the input's width, but the height will be the sum of all the pages' heights. Input:PDF Output:PDF Type:SISO")
|
"This endpoint converts a multi-page PDF document into a single paged PDF"
|
||||||
|
+ " document. The width of the single page will be same as the input's"
|
||||||
|
+ " width, but the height will be the sum of all the pages' heights."
|
||||||
|
+ " Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> pdfToSinglePage(@ModelAttribute PDFFile request)
|
public ResponseEntity<byte[]> pdfToSinglePage(@ModelAttribute PDFFile request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import stirling.software.SPDF.config.RuntimePathConfig;
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
|
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.FileToPdf;
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertHtmlToPDF {
|
public class ConvertHtmlToPDF {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ public class ConvertHtmlToPDF {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ConvertHtmlToPDF(
|
public ConvertHtmlToPDF(
|
||||||
CustomPDDocumentFactory pdfDocumentFactory,
|
CustomPDFDocumentFactory pdfDocumentFactory,
|
||||||
ApplicationProperties applicationProperties,
|
ApplicationProperties applicationProperties,
|
||||||
RuntimePathConfig runtimePathConfig) {
|
RuntimePathConfig runtimePathConfig) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
@ -45,7 +45,8 @@ public class ConvertHtmlToPDF {
|
|||||||
@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. Input:HTML Output:PDF Type:SISO")
|
"This endpoint takes an HTML or ZIP file input and converts it to a PDF format."
|
||||||
|
+ " Input:HTML Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute HTMLToPdfRequest request)
|
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute HTMLToPdfRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
|
@ -33,7 +33,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
|
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
|
||||||
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
|
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.*;
|
import stirling.software.SPDF.utils.*;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
|
||||||
@ -43,10 +43,10 @@ import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
|||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
public class ConvertImgPDFController {
|
public class ConvertImgPDFController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ConvertImgPDFController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public ConvertImgPDFController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,9 @@ public class ConvertImgPDFController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to image(s)",
|
summary = "Convert PDF to image(s)",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a PDF file to image(s) with the specified image format, color type, and DPI. Users can choose to get a single image or multiple images. Input:PDF Output:Image Type:SI-Conditional")
|
"This endpoint converts a PDF file to image(s) with the specified image format,"
|
||||||
|
+ " color type, and DPI. Users can choose to get a single image or multiple"
|
||||||
|
+ " images. Input:PDF Output:Image Type:SI-Conditional")
|
||||||
public ResponseEntity<byte[]> convertToImage(@ModelAttribute ConvertToImageRequest request)
|
public ResponseEntity<byte[]> convertToImage(@ModelAttribute ConvertToImageRequest request)
|
||||||
throws NumberFormatException, Exception {
|
throws NumberFormatException, Exception {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
@ -208,7 +210,9 @@ 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:MISO")
|
"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();
|
||||||
|
@ -25,7 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import stirling.software.SPDF.config.RuntimePathConfig;
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.api.GeneralFile;
|
import stirling.software.SPDF.model.api.GeneralFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.FileToPdf;
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -34,14 +34,14 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertMarkdownToPdf {
|
public class ConvertMarkdownToPdf {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
private final RuntimePathConfig runtimePathConfig;
|
private final RuntimePathConfig runtimePathConfig;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ConvertMarkdownToPdf(
|
public ConvertMarkdownToPdf(
|
||||||
CustomPDDocumentFactory pdfDocumentFactory,
|
CustomPDFDocumentFactory pdfDocumentFactory,
|
||||||
ApplicationProperties applicationProperties,
|
ApplicationProperties applicationProperties,
|
||||||
RuntimePathConfig runtimePathConfig) {
|
RuntimePathConfig runtimePathConfig) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
@ -54,7 +54,8 @@ public class ConvertMarkdownToPdf {
|
|||||||
@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. Input:MARKDOWN Output:PDF Type:SISO")
|
"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();
|
||||||
|
@ -24,7 +24,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import stirling.software.SPDF.config.RuntimePathConfig;
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
||||||
import stirling.software.SPDF.model.api.GeneralFile;
|
import stirling.software.SPDF.model.api.GeneralFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
@ -34,12 +34,12 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertOfficeController {
|
public class ConvertOfficeController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
private final RuntimePathConfig runtimePathConfig;
|
private final RuntimePathConfig runtimePathConfig;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ConvertOfficeController(
|
public ConvertOfficeController(
|
||||||
CustomPDDocumentFactory pdfDocumentFactory, RuntimePathConfig runtimePathConfig) {
|
CustomPDFDocumentFactory pdfDocumentFactory, RuntimePathConfig runtimePathConfig) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
this.runtimePathConfig = runtimePathConfig;
|
this.runtimePathConfig = runtimePathConfig;
|
||||||
}
|
}
|
||||||
@ -93,7 +93,8 @@ public class ConvertOfficeController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a file to a PDF using LibreOffice",
|
summary = "Convert a file to a PDF using LibreOffice",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a given file to a PDF using LibreOffice API Input:ANY Output:PDF Type:SISO")
|
"This endpoint converts a given file to a PDF using LibreOffice API Input:ANY"
|
||||||
|
+ " Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> processFileToPDF(@ModelAttribute GeneralFile request)
|
public ResponseEntity<byte[]> processFileToPDF(@ModelAttribute GeneralFile request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
|
@ -21,7 +21,7 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||||||
import stirling.software.SPDF.model.api.converters.PdfToPresentationRequest;
|
import stirling.software.SPDF.model.api.converters.PdfToPresentationRequest;
|
||||||
import stirling.software.SPDF.model.api.converters.PdfToTextOrRTFRequest;
|
import stirling.software.SPDF.model.api.converters.PdfToTextOrRTFRequest;
|
||||||
import stirling.software.SPDF.model.api.converters.PdfToWordRequest;
|
import stirling.software.SPDF.model.api.converters.PdfToWordRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.PDFToFile;
|
import stirling.software.SPDF.utils.PDFToFile;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -30,10 +30,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
public class ConvertPDFToOffice {
|
public class ConvertPDFToOffice {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ConvertPDFToOffice(CustomPDDocumentFactory pdfDocumentFactory) {
|
public ConvertPDFToOffice(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,8 @@ public class ConvertPDFToOffice {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to Presentation format",
|
summary = "Convert PDF to Presentation format",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a given PDF file to a Presentation format. Input:PDF Output:PPT Type:SISO")
|
"This endpoint converts a given PDF file to a Presentation format. Input:PDF"
|
||||||
|
+ " Output:PPT Type:SISO")
|
||||||
public ResponseEntity<byte[]> processPdfToPresentation(
|
public ResponseEntity<byte[]> processPdfToPresentation(
|
||||||
@ModelAttribute PdfToPresentationRequest request)
|
@ModelAttribute PdfToPresentationRequest request)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
@ -55,7 +56,8 @@ public class ConvertPDFToOffice {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to Text or RTF format",
|
summary = "Convert PDF to Text or RTF format",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a given PDF file to Text or RTF format. Input:PDF Output:TXT Type:SISO")
|
"This endpoint converts a given PDF file to Text or RTF format. Input:PDF"
|
||||||
|
+ " Output:TXT Type:SISO")
|
||||||
public ResponseEntity<byte[]> processPdfToRTForTXT(
|
public ResponseEntity<byte[]> processPdfToRTForTXT(
|
||||||
@ModelAttribute PdfToTextOrRTFRequest request)
|
@ModelAttribute PdfToTextOrRTFRequest request)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
@ -82,7 +84,8 @@ public class ConvertPDFToOffice {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to Word document",
|
summary = "Convert PDF to Word document",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a given PDF file to a Word document format. Input:PDF Output:WORD Type:SISO")
|
"This endpoint converts a given PDF file to a Word document format. Input:PDF"
|
||||||
|
+ " Output:WORD Type:SISO")
|
||||||
public ResponseEntity<byte[]> processPdfToWord(@ModelAttribute PdfToWordRequest request)
|
public ResponseEntity<byte[]> processPdfToWord(@ModelAttribute PdfToWordRequest request)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
@ -95,7 +98,8 @@ public class ConvertPDFToOffice {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to XML",
|
summary = "Convert PDF to XML",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts a PDF file to an XML file. Input:PDF Output:XML Type:SISO")
|
"This endpoint converts a PDF file to an XML file. Input:PDF Output:XML"
|
||||||
|
+ " Type:SISO")
|
||||||
public ResponseEntity<byte[]> processPdfToXML(@ModelAttribute PDFFile request)
|
public ResponseEntity<byte[]> processPdfToXML(@ModelAttribute PDFFile request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
|
@ -21,7 +21,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.config.RuntimePathConfig;
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
||||||
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
|
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
@ -33,12 +33,12 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertWebsiteToPDF {
|
public class ConvertWebsiteToPDF {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
private final RuntimePathConfig runtimePathConfig;
|
private final RuntimePathConfig runtimePathConfig;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ConvertWebsiteToPDF(
|
public ConvertWebsiteToPDF(
|
||||||
CustomPDDocumentFactory pdfDocumentFactory, RuntimePathConfig runtimePathConfig) {
|
CustomPDFDocumentFactory pdfDocumentFactory, RuntimePathConfig runtimePathConfig) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
this.runtimePathConfig = runtimePathConfig;
|
this.runtimePathConfig = runtimePathConfig;
|
||||||
}
|
}
|
||||||
@ -47,7 +47,8 @@ public class ConvertWebsiteToPDF {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a URL to a PDF",
|
summary = "Convert a URL to a PDF",
|
||||||
description =
|
description =
|
||||||
"This endpoint fetches content from a URL and converts it to a PDF format. Input:N/A Output:PDF Type:SISO")
|
"This endpoint fetches content from a URL and converts it to a PDF format."
|
||||||
|
+ " Input:N/A Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> urlToPdf(@ModelAttribute UrlToPdfRequest request)
|
public ResponseEntity<byte[]> urlToPdf(@ModelAttribute UrlToPdfRequest request)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
String URL = request.getUrlInput();
|
String URL = request.getUrlInput();
|
||||||
|
@ -30,7 +30,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||||
import stirling.software.SPDF.pdf.FlexibleCSVWriter;
|
import stirling.software.SPDF.pdf.FlexibleCSVWriter;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
|
|
||||||
import technology.tabula.ObjectExtractor;
|
import technology.tabula.ObjectExtractor;
|
||||||
import technology.tabula.Page;
|
import technology.tabula.Page;
|
||||||
@ -43,10 +43,10 @@ import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class ExtractCSVController {
|
public class ExtractCSVController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ExtractCSVController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public ExtractCSVController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,8 @@ public class ExtractCSVController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extracts a CSV document from a PDF",
|
summary = "Extracts a CSV document from a PDF",
|
||||||
description =
|
description =
|
||||||
"This operation takes an input PDF file and returns CSV file of whole page. Input:PDF Output:CSV Type:SISO")
|
"This operation takes an input PDF file and returns CSV file of whole page."
|
||||||
|
+ " Input:PDF Output:CSV Type:SISO")
|
||||||
public ResponseEntity<?> pdfToCsv(@ModelAttribute PDFWithPageNums form) throws Exception {
|
public ResponseEntity<?> pdfToCsv(@ModelAttribute PDFWithPageNums form) throws Exception {
|
||||||
String baseName = getBaseName(form.getFileInput().getOriginalFilename());
|
String baseName = getBaseName(form.getFileInput().getOriginalFilename());
|
||||||
List<CsvEntry> csvEntries = new ArrayList<>();
|
List<CsvEntry> csvEntries = new ArrayList<>();
|
||||||
|
@ -23,7 +23,7 @@ import stirling.software.SPDF.model.api.filter.ContainsTextRequest;
|
|||||||
import stirling.software.SPDF.model.api.filter.FileSizeRequest;
|
import stirling.software.SPDF.model.api.filter.FileSizeRequest;
|
||||||
import stirling.software.SPDF.model.api.filter.PageRotationRequest;
|
import stirling.software.SPDF.model.api.filter.PageRotationRequest;
|
||||||
import stirling.software.SPDF.model.api.filter.PageSizeRequest;
|
import stirling.software.SPDF.model.api.filter.PageSizeRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -32,10 +32,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Filter", description = "Filter APIs")
|
@Tag(name = "Filter", description = "Filter APIs")
|
||||||
public class FilterController {
|
public class FilterController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public FilterController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public FilterController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.ExtractHeaderRequest;
|
import stirling.software.SPDF.model.api.misc.ExtractHeaderRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -35,10 +35,10 @@ public class AutoRenameController {
|
|||||||
private static final float TITLE_FONT_SIZE_THRESHOLD = 20.0f;
|
private static final float TITLE_FONT_SIZE_THRESHOLD = 20.0f;
|
||||||
private static final int LINE_LIMIT = 200;
|
private static final int LINE_LIMIT = 200;
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public AutoRenameController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public AutoRenameController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,8 @@ public class AutoRenameController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extract header from PDF file",
|
summary = "Extract header from PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint accepts a PDF file and attempts to extract its title or header based on heuristics. Input:PDF Output:PDF Type:SISO")
|
"This endpoint accepts a PDF file and attempts to extract its title or header"
|
||||||
|
+ " based on heuristics. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> extractHeader(@ModelAttribute ExtractHeaderRequest request)
|
public ResponseEntity<byte[]> extractHeader(@ModelAttribute ExtractHeaderRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
|
@ -35,7 +35,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
|
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -51,10 +51,10 @@ public class AutoSplitPdfController {
|
|||||||
"https://github.com/Frooodle/Stirling-PDF",
|
"https://github.com/Frooodle/Stirling-PDF",
|
||||||
"https://stirlingpdf.com"));
|
"https://stirlingpdf.com"));
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public AutoSplitPdfController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public AutoSplitPdfController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
|
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -40,10 +40,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class BlankPageController {
|
public class BlankPageController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public BlankPageController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public BlankPageController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,9 @@ public class BlankPageController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove blank pages from a PDF file",
|
summary = "Remove blank pages from a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint removes blank pages from a given PDF file. Users can specify the threshold and white percentage to tune the detection of blank pages. Input:PDF Output:PDF Type:SISO")
|
"This endpoint removes blank pages from a given PDF file. Users can specify the"
|
||||||
|
+ " threshold and white percentage to tune the detection of blank pages."
|
||||||
|
+ " Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> removeBlankPages(@ModelAttribute RemoveBlankPagesRequest request)
|
public ResponseEntity<byte[]> removeBlankPages(@ModelAttribute RemoveBlankPagesRequest request)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
|
@ -3,13 +3,19 @@ package stirling.software.SPDF.controller.api.misc;
|
|||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
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.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
import javax.imageio.IIOImage;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@ -36,11 +42,15 @@ 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 lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.OptimizePdfRequest;
|
import stirling.software.SPDF.model.api.misc.OptimizePdfRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
import stirling.software.SPDF.utils.ImageProcessingUtils;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
@ -51,87 +61,229 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class CompressController {
|
public class CompressController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public CompressController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public CompressController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compressImagesInPDF(Path pdfFile, double scaleFactor, float jpegQuality)
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
private static class ImageReference {
|
||||||
|
int pageNum; // Page number where the image appears
|
||||||
|
COSName name; // The name used to reference this image
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path compressImagesInPDF(
|
||||||
|
Path pdfFile, double scaleFactor, float jpegQuality, boolean convertToGrayscale)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
byte[] fileBytes = Files.readAllBytes(pdfFile);
|
Path newCompressedPDF = Files.createTempFile("compressedPDF", ".pdf");
|
||||||
long originalFileSize = fileBytes.length;
|
long originalFileSize = Files.size(pdfFile);
|
||||||
log.info(
|
log.info(
|
||||||
"Starting image compression with scale factor: {} and JPEG quality: {} on file size: {}",
|
"Starting image compression with scale factor: {}, JPEG quality: {}, grayscale: {} on file size: {}",
|
||||||
scaleFactor,
|
scaleFactor,
|
||||||
jpegQuality,
|
jpegQuality,
|
||||||
|
convertToGrayscale,
|
||||||
GeneralUtils.formatBytes(originalFileSize));
|
GeneralUtils.formatBytes(originalFileSize));
|
||||||
|
|
||||||
// Track processed images to avoid recompression
|
try (PDDocument doc = pdfDocumentFactory.load(pdfFile)) {
|
||||||
Set<String> processedImages = new HashSet<>();
|
|
||||||
|
// Collect all unique images by content hash
|
||||||
|
Map<String, List<ImageReference>> uniqueImages = new HashMap<>();
|
||||||
|
Map<String, PDImageXObject> compressedVersions = new HashMap<>();
|
||||||
|
|
||||||
try (PDDocument doc = pdfDocumentFactory.load(fileBytes)) {
|
|
||||||
int totalImages = 0;
|
int totalImages = 0;
|
||||||
|
|
||||||
|
for (int pageNum = 0; pageNum < doc.getNumberOfPages(); pageNum++) {
|
||||||
|
PDPage page = doc.getPage(pageNum);
|
||||||
|
PDResources res = page.getResources();
|
||||||
|
if (res == null || res.getXObjectNames() == null) continue;
|
||||||
|
|
||||||
|
for (COSName name : res.getXObjectNames()) {
|
||||||
|
PDXObject xobj = res.getXObject(name);
|
||||||
|
if (!(xobj instanceof PDImageXObject)) continue;
|
||||||
|
|
||||||
|
totalImages++;
|
||||||
|
PDImageXObject image = (PDImageXObject) xobj;
|
||||||
|
String imageHash = generateImageHash(image);
|
||||||
|
|
||||||
|
// Store only page number and name reference
|
||||||
|
ImageReference ref = new ImageReference();
|
||||||
|
ref.pageNum = pageNum;
|
||||||
|
ref.name = name;
|
||||||
|
|
||||||
|
uniqueImages.computeIfAbsent(imageHash, k -> new ArrayList<>()).add(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uniqueImagesCount = uniqueImages.size();
|
||||||
|
int duplicatedImages = totalImages - uniqueImagesCount;
|
||||||
|
log.info(
|
||||||
|
"Found {} unique images and {} duplicated instances across {} pages",
|
||||||
|
uniqueImagesCount,
|
||||||
|
duplicatedImages,
|
||||||
|
doc.getNumberOfPages());
|
||||||
|
|
||||||
|
// SECOND PASS: Process each unique image exactly once
|
||||||
int compressedImages = 0;
|
int compressedImages = 0;
|
||||||
int skippedImages = 0;
|
int skippedImages = 0;
|
||||||
long totalOriginalBytes = 0;
|
long totalOriginalBytes = 0;
|
||||||
long totalCompressedBytes = 0;
|
long totalCompressedBytes = 0;
|
||||||
|
|
||||||
// Minimum dimensions to preserve reasonable quality
|
for (Entry<String, List<ImageReference>> entry : uniqueImages.entrySet()) {
|
||||||
int MIN_WIDTH = 400; // Higher minimum
|
String imageHash = entry.getKey();
|
||||||
int MIN_HEIGHT = 400; // Higher minimum
|
List<ImageReference> references = entry.getValue();
|
||||||
|
|
||||||
log.info("PDF has {} pages", doc.getNumberOfPages());
|
if (references.isEmpty()) continue;
|
||||||
|
|
||||||
for (int pageNum = 0; pageNum < doc.getNumberOfPages(); pageNum++) {
|
// Get the first instance of this image
|
||||||
PDPage page = doc.getPage(pageNum);
|
ImageReference firstRef = references.get(0);
|
||||||
PDResources res = page.getResources();
|
PDPage firstPage = doc.getPage(firstRef.pageNum);
|
||||||
|
PDResources firstPageResources = firstPage.getResources();
|
||||||
|
PDImageXObject originalImage =
|
||||||
|
(PDImageXObject) firstPageResources.getXObject(firstRef.name);
|
||||||
|
|
||||||
if (res == null || res.getXObjectNames() == null) {
|
// Track original size
|
||||||
continue;
|
int originalSize = (int) originalImage.getCOSObject().getLength();
|
||||||
|
totalOriginalBytes += originalSize;
|
||||||
|
|
||||||
|
// Process this unique image once
|
||||||
|
BufferedImage processedImage =
|
||||||
|
processAndCompressImage(
|
||||||
|
originalImage, scaleFactor, jpegQuality, convertToGrayscale);
|
||||||
|
|
||||||
|
if (processedImage != null) {
|
||||||
|
// Convert to bytes for storage
|
||||||
|
byte[] compressedData = convertToBytes(processedImage, jpegQuality);
|
||||||
|
|
||||||
|
// Check if compression is beneficial
|
||||||
|
if (compressedData.length < originalSize || convertToGrayscale) {
|
||||||
|
// Create a single compressed version
|
||||||
|
PDImageXObject compressedImage =
|
||||||
|
PDImageXObject.createFromByteArray(
|
||||||
|
doc,
|
||||||
|
compressedData,
|
||||||
|
originalImage.getCOSObject().toString());
|
||||||
|
|
||||||
|
// Store the compressed version only once in our map
|
||||||
|
compressedVersions.put(imageHash, compressedImage);
|
||||||
|
|
||||||
|
// Report compression stats
|
||||||
|
double reductionPercentage =
|
||||||
|
100.0 - ((compressedData.length * 100.0) / originalSize);
|
||||||
|
log.info(
|
||||||
|
"Image hash {}: Compressed from {} to {} (reduced by {}%)",
|
||||||
|
imageHash,
|
||||||
|
GeneralUtils.formatBytes(originalSize),
|
||||||
|
GeneralUtils.formatBytes(compressedData.length),
|
||||||
|
String.format("%.1f", reductionPercentage));
|
||||||
|
|
||||||
|
// Replace ALL instances with the compressed version
|
||||||
|
for (ImageReference ref : references) {
|
||||||
|
// Get the page and resources when needed
|
||||||
|
PDPage page = doc.getPage(ref.pageNum);
|
||||||
|
PDResources resources = page.getResources();
|
||||||
|
resources.put(ref.name, compressedImage);
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"Replaced image on page {} with compressed version",
|
||||||
|
ref.pageNum + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pageImages = 0;
|
totalCompressedBytes += compressedData.length * references.size();
|
||||||
|
compressedImages++;
|
||||||
for (COSName name : res.getXObjectNames()) {
|
} else {
|
||||||
String imageName = name.getName();
|
log.info("Image hash {}: Compression not beneficial, skipping", imageHash);
|
||||||
|
totalCompressedBytes += originalSize * references.size();
|
||||||
// Skip already processed images
|
|
||||||
if (processedImages.contains(imageName)) {
|
|
||||||
skippedImages++;
|
skippedImages++;
|
||||||
continue;
|
}
|
||||||
|
} else {
|
||||||
|
log.info("Image hash {}: Not suitable for compression, skipping", imageHash);
|
||||||
|
totalCompressedBytes += originalSize * references.size();
|
||||||
|
skippedImages++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PDXObject xobj = res.getXObject(name);
|
// Log compression statistics
|
||||||
if (!(xobj instanceof PDImageXObject)) {
|
double overallImageReduction =
|
||||||
continue;
|
totalOriginalBytes > 0
|
||||||
|
? 100.0 - ((totalCompressedBytes * 100.0) / totalOriginalBytes)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"Image compression summary - Total unique: {}, Compressed: {}, Skipped: {}, Duplicates: {}",
|
||||||
|
uniqueImagesCount,
|
||||||
|
compressedImages,
|
||||||
|
skippedImages,
|
||||||
|
duplicatedImages);
|
||||||
|
log.info(
|
||||||
|
"Total original image size: {}, compressed: {} (reduced by {}%)",
|
||||||
|
GeneralUtils.formatBytes(totalOriginalBytes),
|
||||||
|
GeneralUtils.formatBytes(totalCompressedBytes),
|
||||||
|
String.format("%.1f", overallImageReduction));
|
||||||
|
|
||||||
|
// Free memory before saving
|
||||||
|
compressedVersions.clear();
|
||||||
|
uniqueImages.clear();
|
||||||
|
|
||||||
|
// Save the document
|
||||||
|
log.info("Saving compressed PDF to {}", newCompressedPDF.toString());
|
||||||
|
doc.save(newCompressedPDF.toString());
|
||||||
|
|
||||||
|
// Log overall file size reduction
|
||||||
|
long compressedFileSize = Files.size(newCompressedPDF);
|
||||||
|
double overallReduction = 100.0 - ((compressedFileSize * 100.0) / originalFileSize);
|
||||||
|
log.info(
|
||||||
|
"Overall PDF compression: {} → {} (reduced by {}%)",
|
||||||
|
GeneralUtils.formatBytes(originalFileSize),
|
||||||
|
GeneralUtils.formatBytes(compressedFileSize),
|
||||||
|
String.format("%.1f", overallReduction));
|
||||||
|
return newCompressedPDF;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalImages++;
|
}
|
||||||
pageImages++;
|
|
||||||
PDImageXObject image = (PDImageXObject) xobj;
|
private BufferedImage convertToGrayscale(BufferedImage image) {
|
||||||
|
BufferedImage grayImage =
|
||||||
|
new BufferedImage(
|
||||||
|
image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
|
||||||
|
|
||||||
|
Graphics2D g = grayImage.createGraphics();
|
||||||
|
g.drawImage(image, 0, 0, null);
|
||||||
|
g.dispose();
|
||||||
|
|
||||||
|
return grayImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes and compresses an image if beneficial. Returns the processed image if compression
|
||||||
|
* is worthwhile, null otherwise.
|
||||||
|
*/
|
||||||
|
private BufferedImage processAndCompressImage(
|
||||||
|
PDImageXObject image, double scaleFactor, float jpegQuality, boolean convertToGrayscale)
|
||||||
|
throws IOException {
|
||||||
BufferedImage bufferedImage = image.getImage();
|
BufferedImage bufferedImage = image.getImage();
|
||||||
|
|
||||||
int originalWidth = bufferedImage.getWidth();
|
int originalWidth = bufferedImage.getWidth();
|
||||||
int originalHeight = bufferedImage.getHeight();
|
int originalHeight = bufferedImage.getHeight();
|
||||||
|
|
||||||
log.info(
|
// Minimum dimensions to preserve reasonable quality
|
||||||
"Page {}, Image {}: Original dimensions: {}x{}",
|
int MIN_WIDTH = 400;
|
||||||
pageNum + 1,
|
int MIN_HEIGHT = 400;
|
||||||
imageName,
|
|
||||||
originalWidth,
|
log.info("Original dimensions: {}x{}", originalWidth, originalHeight);
|
||||||
originalHeight);
|
|
||||||
|
|
||||||
// Skip if already small enough
|
// Skip if already small enough
|
||||||
if (originalWidth <= MIN_WIDTH || originalHeight <= MIN_HEIGHT) {
|
if ((originalWidth <= MIN_WIDTH || originalHeight <= MIN_HEIGHT) && !convertToGrayscale) {
|
||||||
log.info(
|
log.info("Skipping - below minimum dimensions threshold");
|
||||||
"Page {}, Image {}: Skipping - below minimum dimensions threshold",
|
return null;
|
||||||
pageNum + 1,
|
}
|
||||||
imageName);
|
|
||||||
skippedImages++;
|
// Convert to grayscale first if requested (before resizing for better quality)
|
||||||
processedImages.add(imageName);
|
if (convertToGrayscale) {
|
||||||
continue;
|
bufferedImage = convertToGrayscale(bufferedImage);
|
||||||
|
log.info("Converted image to grayscale");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust scale factor for very large or very small images
|
// Adjust scale factor for very large or very small images
|
||||||
@ -139,19 +291,11 @@ public class CompressController {
|
|||||||
if (originalWidth > 3000 || originalHeight > 3000) {
|
if (originalWidth > 3000 || originalHeight > 3000) {
|
||||||
// More aggressive for very large images
|
// More aggressive for very large images
|
||||||
adjustedScaleFactor = Math.min(scaleFactor, 0.75);
|
adjustedScaleFactor = Math.min(scaleFactor, 0.75);
|
||||||
log.info(
|
log.info("Very large image, using more aggressive scale: {}", adjustedScaleFactor);
|
||||||
"Page {}, Image {}: Very large image, using more aggressive scale: {}",
|
|
||||||
pageNum + 1,
|
|
||||||
imageName,
|
|
||||||
adjustedScaleFactor);
|
|
||||||
} else if (originalWidth < 1000 || originalHeight < 1000) {
|
} else if (originalWidth < 1000 || originalHeight < 1000) {
|
||||||
// More conservative for smaller images
|
// More conservative for smaller images
|
||||||
adjustedScaleFactor = Math.max(scaleFactor, 0.9);
|
adjustedScaleFactor = Math.max(scaleFactor, 0.9);
|
||||||
log.info(
|
log.info("Smaller image, using conservative scale: {}", adjustedScaleFactor);
|
||||||
"Page {}, Image {}: Smaller image, using conservative scale: {}",
|
|
||||||
pageNum + 1,
|
|
||||||
imageName,
|
|
||||||
adjustedScaleFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int newWidth = (int) (originalWidth * adjustedScaleFactor);
|
int newWidth = (int) (originalWidth * adjustedScaleFactor);
|
||||||
@ -163,195 +307,127 @@ public class CompressController {
|
|||||||
|
|
||||||
// Skip if change is negligible
|
// Skip if change is negligible
|
||||||
if ((double) newWidth / originalWidth > 0.95
|
if ((double) newWidth / originalWidth > 0.95
|
||||||
&& (double) newHeight / originalHeight > 0.95) {
|
&& (double) newHeight / originalHeight > 0.95
|
||||||
log.info(
|
&& !convertToGrayscale) {
|
||||||
"Page {}, Image {}: Change too small, skipping compression",
|
log.info("Change too small, skipping compression");
|
||||||
pageNum + 1,
|
return null;
|
||||||
imageName);
|
|
||||||
skippedImages++;
|
|
||||||
processedImages.add(imageName);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
"Page {}, Image {}: Resizing to {}x{} ({}% of original)",
|
"Resizing to {}x{} ({}% of original)",
|
||||||
pageNum + 1,
|
newWidth, newHeight, Math.round((newWidth * 100.0) / originalWidth));
|
||||||
imageName,
|
|
||||||
newWidth,
|
|
||||||
newHeight,
|
|
||||||
Math.round((newWidth * 100.0) / originalWidth));
|
|
||||||
|
|
||||||
// Use high quality scaling
|
BufferedImage scaledImage;
|
||||||
BufferedImage scaledImage =
|
if (convertToGrayscale) {
|
||||||
|
// If already grayscale, maintain the grayscale format
|
||||||
|
scaledImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_BYTE_GRAY);
|
||||||
|
} else {
|
||||||
|
// Otherwise use original color model
|
||||||
|
scaledImage =
|
||||||
new BufferedImage(
|
new BufferedImage(
|
||||||
newWidth,
|
newWidth,
|
||||||
newHeight,
|
newHeight,
|
||||||
bufferedImage.getColorModel().hasAlpha()
|
bufferedImage.getColorModel().hasAlpha()
|
||||||
? BufferedImage.TYPE_INT_ARGB
|
? BufferedImage.TYPE_INT_ARGB
|
||||||
: BufferedImage.TYPE_INT_RGB);
|
: BufferedImage.TYPE_INT_RGB);
|
||||||
|
}
|
||||||
Graphics2D g2d = scaledImage.createGraphics();
|
Graphics2D g2d = scaledImage.createGraphics();
|
||||||
g2d.setRenderingHint(
|
g2d.setRenderingHint(
|
||||||
RenderingHints.KEY_INTERPOLATION,
|
RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||||
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||||
g2d.setRenderingHint(
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
|
||||||
g2d.setRenderingHint(
|
|
||||||
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
||||||
g2d.drawImage(bufferedImage, 0, 0, newWidth, newHeight, null);
|
g2d.drawImage(bufferedImage, 0, 0, newWidth, newHeight, null);
|
||||||
g2d.dispose();
|
g2d.dispose();
|
||||||
|
|
||||||
// Choose appropriate format and compression
|
return scaledImage;
|
||||||
String format = bufferedImage.getColorModel().hasAlpha() ? "png" : "jpeg";
|
}
|
||||||
|
|
||||||
// First get the actual size of the original image by encoding it to the chosen
|
/**
|
||||||
// format
|
* Converts a BufferedImage to a byte array with specified JPEG quality. Checks if compression
|
||||||
ByteArrayOutputStream originalImageStream = new ByteArrayOutputStream();
|
* is beneficial compared to original.
|
||||||
if (format.equals("jpeg")) {
|
*/
|
||||||
// Get the best available JPEG writer (prioritizes TwelveMonkeys if
|
private byte[] convertToBytes(BufferedImage scaledImage, float jpegQuality) throws IOException {
|
||||||
// available)
|
String format = scaledImage.getColorModel().hasAlpha() ? "png" : "jpeg";
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
if ("jpeg".equals(format)) {
|
||||||
|
// Get the best available JPEG writer
|
||||||
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
|
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
|
||||||
ImageWriter writer = null;
|
ImageWriter writer = writers.next();
|
||||||
|
|
||||||
// Prefer TwelveMonkeys writer if available
|
JPEGImageWriteParam param = (JPEGImageWriteParam) writer.getDefaultWriteParam();
|
||||||
while (writers.hasNext()) {
|
|
||||||
ImageWriter candidate = writers.next();
|
|
||||||
if (candidate.getClass().getName().contains("twelvemonkeys")) {
|
|
||||||
writer = candidate;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (writer == null) {
|
|
||||||
writer = ImageIO.getImageWritersByFormatName("jpeg").next();
|
|
||||||
}
|
|
||||||
|
|
||||||
JPEGImageWriteParam param =
|
// Set compression parameters
|
||||||
(JPEGImageWriteParam) writer.getDefaultWriteParam();
|
|
||||||
|
|
||||||
// Set advanced compression parameters
|
|
||||||
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||||
param.setCompressionQuality(jpegQuality);
|
param.setCompressionQuality(jpegQuality);
|
||||||
param.setOptimizeHuffmanTables(true); // Better compression
|
param.setOptimizeHuffmanTables(true); // Better compression
|
||||||
param.setProgressiveMode(
|
param.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); // Progressive scanning
|
||||||
ImageWriteParam.MODE_DEFAULT); // Progressive scanning
|
|
||||||
|
|
||||||
// Write compressed image
|
// Write compressed image
|
||||||
try (ImageOutputStream ios =
|
try (ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream)) {
|
||||||
ImageIO.createImageOutputStream(originalImageStream)) {
|
|
||||||
writer.setOutput(ios);
|
writer.setOutput(ios);
|
||||||
writer.write(null, new IIOImage(scaledImage, null, null), param);
|
writer.write(null, new IIOImage(scaledImage, null, null), param);
|
||||||
}
|
}
|
||||||
writer.dispose();
|
writer.dispose();
|
||||||
} else {
|
} else {
|
||||||
ImageIO.write(bufferedImage, format, originalImageStream);
|
ImageIO.write(scaledImage, format, outputStream);
|
||||||
}
|
}
|
||||||
int originalEncodedSize = (int) image.getCOSObject().getLength();
|
|
||||||
originalImageStream.close();
|
|
||||||
|
|
||||||
// Now compress the scaled image
|
return outputStream.toByteArray();
|
||||||
ByteArrayOutputStream compressedImageStream = new ByteArrayOutputStream();
|
|
||||||
if (format.equals("jpeg")) {
|
|
||||||
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(format);
|
|
||||||
if (writers.hasNext()) {
|
|
||||||
ImageWriter writer = writers.next();
|
|
||||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
|
||||||
|
|
||||||
if (param.canWriteCompressed()) {
|
|
||||||
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
|
||||||
param.setCompressionQuality(jpegQuality);
|
|
||||||
|
|
||||||
ImageOutputStream imageOut =
|
|
||||||
ImageIO.createImageOutputStream(compressedImageStream);
|
|
||||||
writer.setOutput(imageOut);
|
|
||||||
writer.write(null, new IIOImage(scaledImage, null, null), param);
|
|
||||||
writer.dispose();
|
|
||||||
imageOut.close();
|
|
||||||
} else {
|
|
||||||
ImageIO.write(scaledImage, format, compressedImageStream);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ImageIO.write(scaledImage, format, compressedImageStream);
|
/** Modified hash function to consistently identify identical image content */
|
||||||
|
private String generateImageHash(PDImageXObject image) {
|
||||||
|
try {
|
||||||
|
// Create a stream for the raw stream data
|
||||||
|
try (InputStream stream = image.getCOSObject().createRawInputStream()) {
|
||||||
|
// Read up to first 8KB of data for the hash
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int bytesRead = stream.read(buffer);
|
||||||
|
if (bytesRead > 0) {
|
||||||
|
byte[] dataToHash =
|
||||||
|
bytesRead == buffer.length ? buffer : Arrays.copyOf(buffer, bytesRead);
|
||||||
|
return bytesToHexString(generatMD5(dataToHash));
|
||||||
}
|
}
|
||||||
} else {
|
return "empty-stream";
|
||||||
ImageIO.write(scaledImage, format, compressedImageStream);
|
|
||||||
}
|
}
|
||||||
byte[] imageBytes = compressedImageStream.toByteArray();
|
} catch (Exception e) {
|
||||||
compressedImageStream.close();
|
log.error("Error generating image hash", e);
|
||||||
|
return "fallback-" + System.identityHashCode(image);
|
||||||
// Format sizes using our utility method
|
|
||||||
String originalSizeStr = GeneralUtils.formatBytes(originalEncodedSize);
|
|
||||||
String compressedSizeStr = GeneralUtils.formatBytes(imageBytes.length);
|
|
||||||
|
|
||||||
// Calculate reduction percentage (how much smaller the new file is)
|
|
||||||
double reductionPercentage =
|
|
||||||
100.0 - ((imageBytes.length * 100.0) / originalEncodedSize);
|
|
||||||
|
|
||||||
if (imageBytes.length >= originalEncodedSize) {
|
|
||||||
log.info(
|
|
||||||
"Page {}, Image {}: Compressed size {} not smaller than original {}, skipping replacement",
|
|
||||||
pageNum + 1,
|
|
||||||
imageName,
|
|
||||||
GeneralUtils.formatBytes(imageBytes.length),
|
|
||||||
GeneralUtils.formatBytes(originalEncodedSize));
|
|
||||||
|
|
||||||
// Accumulate original size for both counters (no change)
|
|
||||||
totalOriginalBytes += originalEncodedSize;
|
|
||||||
totalCompressedBytes += originalEncodedSize;
|
|
||||||
skippedImages++;
|
|
||||||
processedImages.add(imageName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
log.info(
|
|
||||||
"Page {}, Image {}: Compressed from {} to {} (reduced by {}%)",
|
|
||||||
pageNum + 1,
|
|
||||||
imageName,
|
|
||||||
originalSizeStr,
|
|
||||||
compressedSizeStr,
|
|
||||||
String.format("%.1f", reductionPercentage));
|
|
||||||
|
|
||||||
// Only replace if compressed size is smaller
|
|
||||||
PDImageXObject compressedImage =
|
|
||||||
PDImageXObject.createFromByteArray(
|
|
||||||
doc, imageBytes, image.getCOSObject().toString());
|
|
||||||
res.put(name, compressedImage);
|
|
||||||
|
|
||||||
// Update counters with compressed size
|
|
||||||
totalOriginalBytes += originalEncodedSize;
|
|
||||||
totalCompressedBytes += imageBytes.length;
|
|
||||||
compressedImages++;
|
|
||||||
processedImages.add(imageName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log overall image compression statistics
|
private String bytesToHexString(byte[] bytes) {
|
||||||
double overallImageReduction =
|
StringBuilder sb = new StringBuilder();
|
||||||
totalOriginalBytes > 0
|
for (byte b : bytes) {
|
||||||
? 100.0 - ((totalCompressedBytes * 100.0) / totalOriginalBytes)
|
sb.append(String.format("%02x", b));
|
||||||
: 0;
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
log.info(
|
private byte[] generatMD5(byte[] data) throws IOException {
|
||||||
"Image compression summary - Total: {}, Compressed: {}, Skipped: {}",
|
try {
|
||||||
totalImages,
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||||
compressedImages,
|
return md.digest(data); // Get the MD5 hash of the image bytes
|
||||||
skippedImages);
|
} catch (NoSuchAlgorithmException e) {
|
||||||
log.info(
|
throw new RuntimeException("MD5 algorithm not available", e);
|
||||||
"Total original image size: {}, compressed: {} (reduced by {:.1f}%)",
|
}
|
||||||
GeneralUtils.formatBytes(totalOriginalBytes),
|
}
|
||||||
GeneralUtils.formatBytes(totalCompressedBytes),
|
|
||||||
overallImageReduction);
|
|
||||||
|
|
||||||
// Save the document
|
private byte[] generateImageMD5(PDImageXObject image) throws IOException {
|
||||||
log.info("Saving compressed PDF to {}", pdfFile.toString());
|
return generatMD5(ImageProcessingUtils.getImageData(image.getImage()));
|
||||||
doc.save(pdfFile.toString());
|
}
|
||||||
|
|
||||||
// Log overall file size reduction
|
/** Generates a hash string from a byte array */
|
||||||
long compressedFileSize = Files.size(pdfFile);
|
private String generateHashFromBytes(byte[] data) {
|
||||||
double overallReduction = 100.0 - ((compressedFileSize * 100.0) / originalFileSize);
|
try {
|
||||||
log.info(
|
// Use the existing method to generate MD5 hash
|
||||||
"Overall PDF compression: {} → {} (reduced by {:.1f}%)",
|
byte[] hash = generatMD5(data);
|
||||||
GeneralUtils.formatBytes(originalFileSize),
|
return bytesToHexString(hash);
|
||||||
GeneralUtils.formatBytes(compressedFileSize),
|
} catch (Exception e) {
|
||||||
overallReduction);
|
log.error("Error generating hash from bytes", e);
|
||||||
|
// Return a unique string as fallback
|
||||||
|
return "fallback-" + System.identityHashCode(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,13 +458,14 @@ public class CompressController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Optimize PDF file",
|
summary = "Optimize PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint accepts a PDF file and optimizes it based on the provided parameters. Input:PDF Output:PDF Type:SISO")
|
"This endpoint accepts a PDF file and optimizes it based on the provided"
|
||||||
|
+ " parameters. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> optimizePdf(@ModelAttribute OptimizePdfRequest request)
|
public ResponseEntity<byte[]> optimizePdf(@ModelAttribute OptimizePdfRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
Integer optimizeLevel = request.getOptimizeLevel();
|
Integer optimizeLevel = request.getOptimizeLevel();
|
||||||
String expectedOutputSizeString = request.getExpectedOutputSize();
|
String expectedOutputSizeString = request.getExpectedOutputSize();
|
||||||
|
Boolean convertToGrayscale = request.getGrayscale();
|
||||||
if (expectedOutputSizeString == null && optimizeLevel == null) {
|
if (expectedOutputSizeString == null && optimizeLevel == null) {
|
||||||
throw new Exception("Both expected output size and optimize level are not specified");
|
throw new Exception("Both expected output size and optimize level are not specified");
|
||||||
}
|
}
|
||||||
@ -400,48 +477,61 @@ public class CompressController {
|
|||||||
autoMode = true;
|
autoMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path tempInputFile = Files.createTempFile("input_", ".pdf");
|
// Create initial input file
|
||||||
inputFile.transferTo(tempInputFile.toFile());
|
Path originalFile = Files.createTempFile("input_", ".pdf");
|
||||||
|
inputFile.transferTo(originalFile.toFile());
|
||||||
|
long inputFileSize = Files.size(originalFile);
|
||||||
|
|
||||||
long inputFileSize = Files.size(tempInputFile);
|
// Start with original as current working file
|
||||||
|
Path currentFile = originalFile;
|
||||||
|
|
||||||
|
// Keep track of all temporary files for cleanup
|
||||||
|
List<Path> tempFiles = new ArrayList<>();
|
||||||
|
tempFiles.add(originalFile);
|
||||||
|
|
||||||
Path tempOutputFile = null;
|
|
||||||
byte[] pdfBytes;
|
|
||||||
try {
|
try {
|
||||||
tempOutputFile = Files.createTempFile("output_", ".pdf");
|
|
||||||
|
|
||||||
if (autoMode) {
|
if (autoMode) {
|
||||||
double sizeReductionRatio = expectedOutputSize / (double) inputFileSize;
|
double sizeReductionRatio = expectedOutputSize / (double) inputFileSize;
|
||||||
optimizeLevel = determineOptimizeLevel(sizeReductionRatio);
|
optimizeLevel = determineOptimizeLevel(sizeReductionRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean sizeMet = false;
|
boolean sizeMet = false;
|
||||||
boolean imageCompressionApplied = false; // Track if we've already compressed images
|
boolean imageCompressionApplied = false;
|
||||||
boolean qpdfCompressionApplied = false;
|
boolean qpdfCompressionApplied = false;
|
||||||
|
|
||||||
while (!sizeMet && optimizeLevel <= 9) {
|
while (!sizeMet && optimizeLevel <= 9) {
|
||||||
// Apply appropriate compression based on level
|
// Apply image compression for levels 4-9
|
||||||
|
if ((optimizeLevel >= 4 || Boolean.TRUE.equals(convertToGrayscale))
|
||||||
// Levels 4-9: Apply image compression
|
&& !imageCompressionApplied) {
|
||||||
if (optimizeLevel >= 4 && !imageCompressionApplied) {
|
|
||||||
double scaleFactor = getScaleFactorForLevel(optimizeLevel);
|
double scaleFactor = getScaleFactorForLevel(optimizeLevel);
|
||||||
float jpegQuality = getJpegQualityForLevel(optimizeLevel);
|
float jpegQuality = getJpegQualityForLevel(optimizeLevel);
|
||||||
compressImagesInPDF(tempInputFile, scaleFactor, jpegQuality);
|
|
||||||
imageCompressionApplied = true; // Mark that we've compressed images
|
// Use the returned path from compressImagesInPDF
|
||||||
|
Path compressedImageFile = compressImagesInPDF(
|
||||||
|
currentFile,
|
||||||
|
scaleFactor,
|
||||||
|
jpegQuality,
|
||||||
|
Boolean.TRUE.equals(convertToGrayscale));
|
||||||
|
|
||||||
|
// Add to temp files list and update current file
|
||||||
|
tempFiles.add(compressedImageFile);
|
||||||
|
currentFile = compressedImageFile;
|
||||||
|
imageCompressionApplied = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All levels (1-9): Apply QPDF compression
|
// Apply QPDF compression for all levels
|
||||||
if (!qpdfCompressionApplied) {
|
if (!qpdfCompressionApplied) {
|
||||||
long preQpdfSize = Files.size(tempInputFile);
|
long preQpdfSize = Files.size(currentFile);
|
||||||
log.info("Pre-QPDF file size: {}", GeneralUtils.formatBytes(preQpdfSize));
|
log.info("Pre-QPDF file size: {}", GeneralUtils.formatBytes(preQpdfSize));
|
||||||
|
|
||||||
// For levels 1-3, map to qpdf compression levels 1-9
|
// Map optimization levels to QPDF compression levels
|
||||||
int qpdfCompressionLevel = optimizeLevel;
|
int qpdfCompressionLevel = optimizeLevel <= 3
|
||||||
if (optimizeLevel <= 3) {
|
? optimizeLevel * 3 // Level 1->3, 2->6, 3->9
|
||||||
qpdfCompressionLevel = optimizeLevel * 3; // Level 1->3, 2->6, 3->9
|
: 9; // Max compression for levels 4-9
|
||||||
} else {
|
|
||||||
qpdfCompressionLevel = 9; // Max QPDF compression for levels 4-9
|
// Create output file for QPDF
|
||||||
}
|
Path qpdfOutputFile = Files.createTempFile("qpdf_output_", ".pdf");
|
||||||
|
tempFiles.add(qpdfOutputFile);
|
||||||
|
|
||||||
// Run QPDF optimization
|
// Run QPDF optimization
|
||||||
List<String> command = new ArrayList<>();
|
List<String> command = new ArrayList<>();
|
||||||
@ -456,48 +546,50 @@ public class CompressController {
|
|||||||
command.add("--compression-level=" + qpdfCompressionLevel);
|
command.add("--compression-level=" + qpdfCompressionLevel);
|
||||||
command.add("--compress-streams=y");
|
command.add("--compress-streams=y");
|
||||||
command.add("--object-streams=generate");
|
command.add("--object-streams=generate");
|
||||||
command.add(tempInputFile.toString());
|
command.add(currentFile.toString());
|
||||||
command.add(tempOutputFile.toString());
|
command.add(qpdfOutputFile.toString());
|
||||||
|
|
||||||
ProcessExecutorResult returnCode = null;
|
ProcessExecutorResult returnCode = null;
|
||||||
try {
|
try {
|
||||||
returnCode =
|
returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF)
|
||||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.QPDF)
|
|
||||||
.runCommandWithOutputHandling(command);
|
.runCommandWithOutputHandling(command);
|
||||||
qpdfCompressionApplied = true;
|
qpdfCompressionApplied = true;
|
||||||
|
|
||||||
|
// Update current file to the QPDF output
|
||||||
|
currentFile = qpdfOutputFile;
|
||||||
|
|
||||||
|
long postQpdfSize = Files.size(currentFile);
|
||||||
|
double qpdfReduction = 100.0 - ((postQpdfSize * 100.0) / preQpdfSize);
|
||||||
|
log.info(
|
||||||
|
"Post-QPDF file size: {} (reduced by {}%)",
|
||||||
|
GeneralUtils.formatBytes(postQpdfSize),
|
||||||
|
String.format("%.1f", qpdfReduction));
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (returnCode != null && returnCode.getRc() != 3) {
|
if (returnCode != null && returnCode.getRc() != 3) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
// If QPDF fails, keep using the current file
|
||||||
|
log.warn("QPDF compression failed, continuing with current file");
|
||||||
}
|
}
|
||||||
long postQpdfSize = Files.size(tempOutputFile);
|
|
||||||
double qpdfReduction = 100.0 - ((postQpdfSize * 100.0) / preQpdfSize);
|
|
||||||
log.info(
|
|
||||||
"Post-QPDF file size: {} (reduced by {:.1f}%)",
|
|
||||||
GeneralUtils.formatBytes(postQpdfSize), qpdfReduction);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
tempOutputFile = tempInputFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if file size is within expected size or not auto mode
|
// Check if file size is within expected size or not auto mode
|
||||||
long outputFileSize = Files.size(tempOutputFile);
|
long outputFileSize = Files.size(currentFile);
|
||||||
if (outputFileSize <= expectedOutputSize || !autoMode) {
|
if (outputFileSize <= expectedOutputSize || !autoMode) {
|
||||||
sizeMet = true;
|
sizeMet = true;
|
||||||
} else {
|
} else {
|
||||||
int newOptimizeLevel =
|
int newOptimizeLevel = incrementOptimizeLevel(
|
||||||
incrementOptimizeLevel(
|
|
||||||
optimizeLevel, outputFileSize, expectedOutputSize);
|
optimizeLevel, outputFileSize, expectedOutputSize);
|
||||||
|
|
||||||
// Check if we can't increase the level further
|
// Check if we can't increase the level further
|
||||||
if (newOptimizeLevel == optimizeLevel) {
|
if (newOptimizeLevel == optimizeLevel) {
|
||||||
if (autoMode) {
|
if (autoMode) {
|
||||||
log.info(
|
log.info("Maximum optimization level reached without meeting target size.");
|
||||||
"Maximum optimization level reached without meeting target size.");
|
|
||||||
sizeMet = true;
|
sizeMet = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Reset image compression if moving to a new level
|
// Reset flags for next iteration with higher optimization level
|
||||||
imageCompressionApplied = false;
|
imageCompressionApplied = false;
|
||||||
qpdfCompressionApplied = false;
|
qpdfCompressionApplied = false;
|
||||||
optimizeLevel = newOptimizeLevel;
|
optimizeLevel = newOptimizeLevel;
|
||||||
@ -505,26 +597,30 @@ public class CompressController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the optimized PDF file
|
|
||||||
pdfBytes = Files.readAllBytes(tempOutputFile);
|
|
||||||
Path finalFile = tempOutputFile;
|
|
||||||
|
|
||||||
// Check if optimized file is larger than the original
|
// Check if optimized file is larger than the original
|
||||||
if (pdfBytes.length > inputFileSize) {
|
long finalFileSize = Files.size(currentFile);
|
||||||
log.warn(
|
if (finalFileSize > inputFileSize) {
|
||||||
"Optimized file is larger than the original. Returning the original file instead.");
|
log.warn("Optimized file is larger than the original. Using the original file instead.");
|
||||||
finalFile = tempInputFile;
|
// Use the stored reference to the original file
|
||||||
|
currentFile = originalFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
String outputFilename =
|
String outputFilename = Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
||||||
Filenames.toSimpleFileName(inputFile.getOriginalFilename())
|
|
||||||
.replaceFirst("[.][^.]+$", "")
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_Optimized.pdf";
|
+ "_Optimized.pdf";
|
||||||
|
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
pdfDocumentFactory.load(finalFile.toFile()), outputFilename);
|
pdfDocumentFactory.load(currentFile.toFile()), outputFilename);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
Files.deleteIfExists(tempOutputFile);
|
// Clean up all temporary files
|
||||||
|
for (Path tempFile : tempFiles) {
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(tempFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Failed to delete temporary file: " + tempFile, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -34,10 +34,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class DecompressPdfController {
|
public class DecompressPdfController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public DecompressPdfController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public DecompressPdfController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
|
import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.CheckProgramInstall;
|
import stirling.software.SPDF.utils.CheckProgramInstall;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
@ -46,10 +46,10 @@ public class ExtractImageScansController {
|
|||||||
|
|
||||||
private static final String REPLACEFIRST = "[.][^.]+$";
|
private static final String REPLACEFIRST = "[.][^.]+$";
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ExtractImageScansController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public ExtractImageScansController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +57,10 @@ public class ExtractImageScansController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extract image scans from an input file",
|
summary = "Extract image scans from an input file",
|
||||||
description =
|
description =
|
||||||
"This endpoint extracts image scans from a given file based on certain parameters. Users can specify angle threshold, tolerance, minimum area, minimum contour area, and border size. Input:PDF Output:IMAGE/ZIP Type:SIMO")
|
"This endpoint extracts image scans from a given file based on certain"
|
||||||
|
+ " parameters. Users can specify angle threshold, tolerance, minimum area,"
|
||||||
|
+ " minimum contour area, and border size. Input:PDF Output:IMAGE/ZIP"
|
||||||
|
+ " Type:SIMO")
|
||||||
public ResponseEntity<byte[]> extractImageScans(
|
public ResponseEntity<byte[]> extractImageScans(
|
||||||
@RequestBody(
|
@RequestBody(
|
||||||
description = "Form data containing file and extraction parameters",
|
description = "Form data containing file and extraction parameters",
|
||||||
|
@ -40,7 +40,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFExtractImagesRequest;
|
import stirling.software.SPDF.model.api.PDFExtractImagesRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.ImageProcessingUtils;
|
import stirling.software.SPDF.utils.ImageProcessingUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -50,10 +50,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class ExtractImagesController {
|
public class ExtractImagesController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ExtractImagesController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public ExtractImagesController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,9 @@ public class ExtractImagesController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extract images from a PDF file",
|
summary = "Extract images from a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint extracts images from a given PDF file and returns them in a zip file. Users can specify the output image format. Input:PDF Output:IMAGE/ZIP Type:SIMO")
|
"This endpoint extracts images from a given PDF file and returns them in a zip"
|
||||||
|
+ " file. Users can specify the output image format. Input:PDF"
|
||||||
|
+ " Output:IMAGE/ZIP Type:SIMO")
|
||||||
public ResponseEntity<byte[]> extractImages(@ModelAttribute PDFExtractImagesRequest request)
|
public ResponseEntity<byte[]> extractImages(@ModelAttribute PDFExtractImagesRequest request)
|
||||||
throws IOException, InterruptedException, ExecutionException {
|
throws IOException, InterruptedException, ExecutionException {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
|
@ -26,7 +26,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.FlattenRequest;
|
import stirling.software.SPDF.model.api.misc.FlattenRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -35,10 +35,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class FlattenController {
|
public class FlattenController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public FlattenController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public FlattenController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,8 @@ public class FlattenController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Flatten PDF form fields or full page",
|
summary = "Flatten PDF form fields or full page",
|
||||||
description =
|
description =
|
||||||
"Flattening just PDF form fields or converting each page to images to make text unselectable. Input:PDF, Output:PDF. Type:SISO")
|
"Flattening just PDF form fields or converting each page to images to make text"
|
||||||
|
+ " unselectable. Input:PDF, Output:PDF. Type:SISO")
|
||||||
public ResponseEntity<byte[]> flatten(@ModelAttribute FlattenRequest request) throws Exception {
|
public ResponseEntity<byte[]> flatten(@ModelAttribute FlattenRequest request) throws Exception {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.MetadataRequest;
|
import stirling.software.SPDF.model.api.misc.MetadataRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
import stirling.software.SPDF.utils.propertyeditor.StringToMapPropertyEditor;
|
import stirling.software.SPDF.utils.propertyeditor.StringToMapPropertyEditor;
|
||||||
|
|
||||||
@ -33,10 +33,10 @@ import stirling.software.SPDF.utils.propertyeditor.StringToMapPropertyEditor;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class MetadataController {
|
public class MetadataController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public MetadataController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public MetadataController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +59,9 @@ public class MetadataController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Update metadata of a PDF file",
|
summary = "Update metadata of a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint allows you to update the metadata of a given PDF file. You can add, modify, or delete standard and custom metadata fields. Input:PDF Output:PDF Type:SISO")
|
"This endpoint allows you to update the metadata of a given PDF file. You can"
|
||||||
|
+ " add, modify, or delete standard and custom metadata fields. Input:PDF"
|
||||||
|
+ " Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> metadata(@ModelAttribute MetadataRequest request)
|
public ResponseEntity<byte[]> metadata(@ModelAttribute MetadataRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.api.misc.ProcessPdfWithOcrRequest;
|
import stirling.software.SPDF.model.api.misc.ProcessPdfWithOcrRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/misc")
|
@RequestMapping("/api/v1/misc")
|
||||||
@ -43,11 +43,11 @@ public class OCRController {
|
|||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
public OCRController(
|
public OCRController(
|
||||||
ApplicationProperties applicationProperties,
|
ApplicationProperties applicationProperties,
|
||||||
CustomPDDocumentFactory pdfDocumentFactory) {
|
CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.applicationProperties = applicationProperties;
|
this.applicationProperties = applicationProperties;
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
@ -70,7 +70,9 @@ public class OCRController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Process PDF files with OCR using Tesseract",
|
summary = "Process PDF files with OCR using Tesseract",
|
||||||
description =
|
description =
|
||||||
"Takes a PDF file as input, performs OCR using specified languages and OCR type (skip-text/force-ocr), and returns the processed PDF. Input:PDF Output:PDF Type:SISO")
|
"Takes a PDF file as input, performs OCR using specified languages and OCR type"
|
||||||
|
+ " (skip-text/force-ocr), and returns the processed PDF. Input:PDF"
|
||||||
|
+ " Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> processPdfWithOCR(
|
public ResponseEntity<byte[]> processPdfWithOCR(
|
||||||
@ModelAttribute ProcessPdfWithOcrRequest request)
|
@ModelAttribute ProcessPdfWithOcrRequest request)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
|
@ -18,7 +18,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.OverlayImageRequest;
|
import stirling.software.SPDF.model.api.misc.OverlayImageRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -28,10 +28,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class OverlayImageController {
|
public class OverlayImageController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public OverlayImageController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public OverlayImageController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +39,9 @@ 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: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();
|
||||||
|
@ -24,7 +24,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.misc.AddPageNumbersRequest;
|
import stirling.software.SPDF.model.api.misc.AddPageNumbersRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -33,10 +33,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class PageNumbersController {
|
public class PageNumbersController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public PageNumbersController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public PageNumbersController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,8 @@ public class PageNumbersController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add page numbers to a PDF document",
|
summary = "Add page numbers to a PDF document",
|
||||||
description =
|
description =
|
||||||
"This operation takes an input PDF file and adds page numbers to it. Input:PDF Output:PDF Type:SISO")
|
"This operation takes an input PDF file and adds page numbers to it. Input:PDF"
|
||||||
|
+ " Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> addPageNumbers(@ModelAttribute AddPageNumbersRequest request)
|
public ResponseEntity<byte[]> addPageNumbers(@ModelAttribute AddPageNumbersRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
|
@ -19,7 +19,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.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
@ -29,10 +29,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class RepairController {
|
public class RepairController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public RepairController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public RepairController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,9 @@ public class RepairController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Repair a PDF file",
|
summary = "Repair a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint repairs a given PDF file by running qpdf command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response. Input:PDF Output:PDF Type:SISO")
|
"This endpoint repairs a given PDF file by running qpdf command. The PDF is"
|
||||||
|
+ " first saved to a temporary location, repaired, read back, and then"
|
||||||
|
+ " returned as a response. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> repairPdf(@ModelAttribute PDFFile request)
|
public ResponseEntity<byte[]> repairPdf(@ModelAttribute PDFFile request)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
|
@ -20,7 +20,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.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -28,10 +28,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class ShowJavascript {
|
public class ShowJavascript {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ShowJavascript(CustomPDDocumentFactory pdfDocumentFactory) {
|
public ShowJavascript(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,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.misc.AddStampRequest;
|
import stirling.software.SPDF.model.api.misc.AddStampRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -46,10 +46,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class StampController {
|
public class StampController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public StampController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public StampController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +57,9 @@ public class StampController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add stamp to a PDF file",
|
summary = "Add stamp to a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint adds a stamp to a given PDF file. Users can specify the stamp type (text or image), rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO")
|
"This endpoint adds a stamp to a given PDF file. Users can specify the stamp"
|
||||||
|
+ " type (text or image), rotation, opacity, width spacer, and height"
|
||||||
|
+ " spacer. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request)
|
public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request)
|
||||||
throws IOException, Exception {
|
throws IOException, Exception {
|
||||||
MultipartFile pdfFile = request.getFileInput();
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
|
@ -68,7 +68,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.security.SignPDFWithCertRequest;
|
import stirling.software.SPDF.model.api.security.SignPDFWithCertRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -81,15 +81,15 @@ public class CertSignController {
|
|||||||
Security.addProvider(new BouncyCastleProvider());
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public CertSignController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public CertSignController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sign(
|
private static void sign(
|
||||||
CustomPDDocumentFactory pdfDocumentFactory,
|
CustomPDFDocumentFactory pdfDocumentFactory,
|
||||||
MultipartFile input,
|
MultipartFile input,
|
||||||
OutputStream output,
|
OutputStream output,
|
||||||
CreateSignature instance,
|
CreateSignature instance,
|
||||||
|
@ -62,7 +62,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -73,10 +73,10 @@ public class GetInfoOnPDF {
|
|||||||
|
|
||||||
static ObjectMapper objectMapper = new ObjectMapper();
|
static ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public GetInfoOnPDF(CustomPDDocumentFactory pdfDocumentFactory) {
|
public GetInfoOnPDF(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.api.security.AddPasswordRequest;
|
import stirling.software.SPDF.model.api.security.AddPasswordRequest;
|
||||||
import stirling.software.SPDF.model.api.security.PDFPasswordRequest;
|
import stirling.software.SPDF.model.api.security.PDFPasswordRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -27,10 +27,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class PasswordController {
|
public class PasswordController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public PasswordController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public PasswordController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ public class PasswordController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove password from a PDF file",
|
summary = "Remove password from a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint removes the password from a protected PDF file. Users need to provide the"
|
"This endpoint removes the password from a protected PDF file. Users need to"
|
||||||
+ " existing password. Input:PDF Output:PDF Type:SISO")
|
+ " provide the existing password. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> removePassword(@ModelAttribute PDFPasswordRequest request)
|
public ResponseEntity<byte[]> removePassword(@ModelAttribute PDFPasswordRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
@ -57,8 +57,9 @@ public class PasswordController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add password to a PDF file",
|
summary = "Add password to a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint adds password protection to a PDF file. Users can specify a set of"
|
"This endpoint adds password protection to a PDF file. Users can specify a set"
|
||||||
+ " permissions that should be applied to the file. Input:PDF Output:PDF")
|
+ " of permissions that should be applied to the file. Input:PDF"
|
||||||
|
+ " Output:PDF")
|
||||||
public ResponseEntity<byte[]> addPassword(@ModelAttribute AddPasswordRequest request)
|
public ResponseEntity<byte[]> addPassword(@ModelAttribute AddPasswordRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
|
@ -35,7 +35,7 @@ import stirling.software.SPDF.model.api.security.ManualRedactPdfRequest;
|
|||||||
import stirling.software.SPDF.model.api.security.RedactPdfRequest;
|
import stirling.software.SPDF.model.api.security.RedactPdfRequest;
|
||||||
import stirling.software.SPDF.model.api.security.RedactionArea;
|
import stirling.software.SPDF.model.api.security.RedactionArea;
|
||||||
import stirling.software.SPDF.pdf.TextFinder;
|
import stirling.software.SPDF.pdf.TextFinder;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
@ -47,10 +47,10 @@ import stirling.software.SPDF.utils.propertyeditor.StringToArrayListPropertyEdit
|
|||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class RedactController {
|
public class RedactController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public RedactController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public RedactController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,9 @@ public class RedactController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Redacts areas and pages in a PDF document",
|
summary = "Redacts areas and pages in a PDF document",
|
||||||
description =
|
description =
|
||||||
"This operation takes an input PDF file with a list of areas, page number(s)/range(s)/function(s) to redact. Input:PDF, Output:PDF, Type:SISO")
|
"This operation takes an input PDF file with a list of areas, page"
|
||||||
|
+ " number(s)/range(s)/function(s) to redact. Input:PDF, Output:PDF,"
|
||||||
|
+ " Type:SISO")
|
||||||
public ResponseEntity<byte[]> redactPDF(@ModelAttribute ManualRedactPdfRequest request)
|
public ResponseEntity<byte[]> redactPDF(@ModelAttribute ManualRedactPdfRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
@ -196,8 +198,8 @@ public class RedactController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Redacts listOfText in a PDF document",
|
summary = "Redacts listOfText in a PDF document",
|
||||||
description =
|
description =
|
||||||
"This operation takes an input PDF file and redacts the provided listOfText. Input:PDF,"
|
"This operation takes an input PDF file and redacts the provided listOfText."
|
||||||
+ " Output:PDF, Type:SISO")
|
+ " Input:PDF, Output:PDF, Type:SISO")
|
||||||
public ResponseEntity<byte[]> redactPdf(@ModelAttribute RedactPdfRequest request)
|
public ResponseEntity<byte[]> redactPdf(@ModelAttribute RedactPdfRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
|
@ -21,7 +21,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.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -29,10 +29,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class RemoveCertSignController {
|
public class RemoveCertSignController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public RemoveCertSignController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public RemoveCertSignController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,8 @@ public class RemoveCertSignController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove digital signature from PDF",
|
summary = "Remove digital signature from PDF",
|
||||||
description =
|
description =
|
||||||
"This endpoint accepts a PDF file and returns the PDF file without the digital signature. Input:PDF, Output:PDF Type:SISO")
|
"This endpoint accepts a PDF file and returns the PDF file without the digital"
|
||||||
|
+ " signature. Input:PDF, Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> removeCertSignPDF(@ModelAttribute PDFFile request)
|
public ResponseEntity<byte[]> removeCertSignPDF(@ModelAttribute PDFFile request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile pdf = request.getFileInput();
|
MultipartFile pdf = request.getFileInput();
|
||||||
|
@ -25,7 +25,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.security.SanitizePdfRequest;
|
import stirling.software.SPDF.model.api.security.SanitizePdfRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -33,10 +33,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class SanitizeController {
|
public class SanitizeController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SanitizeController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public SanitizeController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,19 +35,19 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import stirling.software.SPDF.model.api.security.SignatureValidationRequest;
|
import stirling.software.SPDF.model.api.security.SignatureValidationRequest;
|
||||||
import stirling.software.SPDF.model.api.security.SignatureValidationResult;
|
import stirling.software.SPDF.model.api.security.SignatureValidationResult;
|
||||||
import stirling.software.SPDF.service.CertificateValidationService;
|
import stirling.software.SPDF.service.CertificateValidationService;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/security")
|
@RequestMapping("/api/v1/security")
|
||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class ValidateSignatureController {
|
public class ValidateSignatureController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
private final CertificateValidationService certValidationService;
|
private final CertificateValidationService certValidationService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ValidateSignatureController(
|
public ValidateSignatureController(
|
||||||
CustomPDDocumentFactory pdfDocumentFactory,
|
CustomPDFDocumentFactory pdfDocumentFactory,
|
||||||
CertificateValidationService certValidationService) {
|
CertificateValidationService certValidationService) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
this.certValidationService = certValidationService;
|
this.certValidationService = certValidationService;
|
||||||
@ -56,7 +56,8 @@ public class ValidateSignatureController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Validate PDF Digital Signature",
|
summary = "Validate PDF Digital Signature",
|
||||||
description =
|
description =
|
||||||
"Validates the digital signatures in a PDF file against default or custom certificates. Input:PDF Output:JSON Type:SISO")
|
"Validates the digital signatures in a PDF file against default or custom"
|
||||||
|
+ " certificates. Input:PDF Output:JSON Type:SISO")
|
||||||
@PostMapping(value = "/validate-signature")
|
@PostMapping(value = "/validate-signature")
|
||||||
public ResponseEntity<List<SignatureValidationResult>> validateSignature(
|
public ResponseEntity<List<SignatureValidationResult>> validateSignature(
|
||||||
@ModelAttribute SignatureValidationRequest request) throws IOException {
|
@ModelAttribute SignatureValidationRequest request) throws IOException {
|
||||||
|
@ -36,7 +36,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.security.AddWatermarkRequest;
|
import stirling.software.SPDF.model.api.security.AddWatermarkRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@ -45,10 +45,10 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class WatermarkController {
|
public class WatermarkController {
|
||||||
|
|
||||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public WatermarkController(CustomPDDocumentFactory pdfDocumentFactory) {
|
public WatermarkController(CustomPDFDocumentFactory pdfDocumentFactory) {
|
||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,9 @@ public class WatermarkController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add watermark to a PDF file",
|
summary = "Add watermark to a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint adds a watermark 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")
|
"This endpoint adds a watermark 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[]> addWatermark(@ModelAttribute AddWatermarkRequest request)
|
public ResponseEntity<byte[]> addWatermark(@ModelAttribute AddWatermarkRequest request)
|
||||||
throws IOException, Exception {
|
throws IOException, Exception {
|
||||||
MultipartFile pdfFile = request.getFileInput();
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
|
@ -29,7 +29,7 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CustomPDDocumentFactory {
|
public class CustomPDFDocumentFactory {
|
||||||
|
|
||||||
private final PdfMetadataService pdfMetadataService;
|
private final PdfMetadataService pdfMetadataService;
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ public class CustomPDDocumentFactory {
|
|||||||
// Counter for tracking temporary resources
|
// Counter for tracking temporary resources
|
||||||
private static final AtomicLong tempCounter = new AtomicLong(0);
|
private static final AtomicLong tempCounter = new AtomicLong(0);
|
||||||
|
|
||||||
public CustomPDDocumentFactory(PdfMetadataService pdfMetadataService) {
|
public CustomPDFDocumentFactory(PdfMetadataService pdfMetadataService) {
|
||||||
this.pdfMetadataService = pdfMetadataService;
|
this.pdfMetadataService = pdfMetadataService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +82,21 @@ public class CustomPDDocumentFactory {
|
|||||||
return loadAdaptively(file, fileSize);
|
return loadAdaptively(file, fileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main entry point for loading a PDF document from a Path. Automatically selects the most
|
||||||
|
* appropriate loading strategy.
|
||||||
|
*/
|
||||||
|
public PDDocument load(Path path) throws IOException {
|
||||||
|
if (path == null) {
|
||||||
|
throw new IllegalArgumentException("File cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
long fileSize = Files.size(path);
|
||||||
|
log.info("Loading PDF from file, size: {}MB", fileSize / (1024 * 1024));
|
||||||
|
|
||||||
|
return loadAdaptively(path.toFile(), fileSize);
|
||||||
|
}
|
||||||
|
|
||||||
/** Load a PDF from byte array with automatic optimization. */
|
/** Load a PDF from byte array with automatic optimization. */
|
||||||
public PDDocument load(byte[] input) throws IOException {
|
public PDDocument load(byte[] input) throws IOException {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
@ -246,6 +261,7 @@ public class CustomPDDocumentFactory {
|
|||||||
removePassword(doc);
|
removePassword(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private PDDocument loadFromFile(File file, long size, StreamCacheCreateFunction cache)
|
private PDDocument loadFromFile(File file, long size, StreamCacheCreateFunction cache)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return Loader.loadPDF(new DeletingRandomAccessFile(file), "", null, null, cache);
|
return Loader.loadPDF(new DeletingRandomAccessFile(file), "", null, null, cache);
|
@ -35,7 +35,7 @@ import io.github.pixee.security.Filenames;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PdfUtils {
|
public class PdfUtils {
|
||||||
@ -127,7 +127,7 @@ public class PdfUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] convertFromPdf(
|
public static byte[] convertFromPdf(
|
||||||
CustomPDDocumentFactory pdfDocumentFactory,
|
CustomPDFDocumentFactory pdfDocumentFactory,
|
||||||
byte[] inputStream,
|
byte[] inputStream,
|
||||||
String imageType,
|
String imageType,
|
||||||
ImageType colorType,
|
ImageType colorType,
|
||||||
@ -315,7 +315,7 @@ public class PdfUtils {
|
|||||||
String fitOption,
|
String fitOption,
|
||||||
boolean autoRotate,
|
boolean autoRotate,
|
||||||
String colorType,
|
String colorType,
|
||||||
CustomPDDocumentFactory pdfDocumentFactory)
|
CustomPDFDocumentFactory pdfDocumentFactory)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
try (PDDocument doc = pdfDocumentFactory.createNewDocument()) {
|
try (PDDocument doc = pdfDocumentFactory.createNewDocument()) {
|
||||||
for (MultipartFile file : files) {
|
for (MultipartFile file : files) {
|
||||||
@ -405,7 +405,7 @@ public class PdfUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] overlayImage(
|
public static byte[] overlayImage(
|
||||||
CustomPDDocumentFactory pdfDocumentFactory,
|
CustomPDFDocumentFactory pdfDocumentFactory,
|
||||||
byte[] pdfBytes,
|
byte[] pdfBytes,
|
||||||
byte[] imageBytes,
|
byte[] imageBytes,
|
||||||
float x,
|
float x,
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=إصلاح
|
repair.title=إصلاح
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Son səhifə
|
|||||||
sign.next=Növbəti səhifə
|
sign.next=Növbəti səhifə
|
||||||
sign.previous=Əvvəlki səhifə
|
sign.previous=Əvvəlki səhifə
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Bərpa Et
|
repair.title=Bərpa Et
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Последна страница
|
|||||||
sign.next=Следваща страница
|
sign.next=Следваща страница
|
||||||
sign.previous=Предишна стараница
|
sign.previous=Предишна стараница
|
||||||
sign.maintainRatio=Превключване за поддържане на съотношението на страните
|
sign.maintainRatio=Превключване за поддържане на съотношението на страните
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Поправи
|
repair.title=Поправи
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Poslední stránka
|
|||||||
sign.next=Další stránka
|
sign.next=Další stránka
|
||||||
sign.previous=Předchozí stránka
|
sign.previous=Předchozí stránka
|
||||||
sign.maintainRatio=Přepnout zachování poměru stran
|
sign.maintainRatio=Přepnout zachování poměru stran
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Opravit
|
repair.title=Opravit
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparér
|
repair.title=Reparér
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Letzte Seite
|
|||||||
sign.next=Nächste Seite
|
sign.next=Nächste Seite
|
||||||
sign.previous=Vorherige Seite
|
sign.previous=Vorherige Seite
|
||||||
sign.maintainRatio=Seitenverhältnis beibehalten ein-/ausschalten
|
sign.maintainRatio=Seitenverhältnis beibehalten ein-/ausschalten
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparieren
|
repair.title=Reparieren
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Τελευταία σελίδα
|
|||||||
sign.next=Επόμενη σελίδα
|
sign.next=Επόμενη σελίδα
|
||||||
sign.previous=Προηγούμενη σελίδα
|
sign.previous=Προηγούμενη σελίδα
|
||||||
sign.maintainRatio=Εναλλαγή διατήρησης αναλογίας διαστάσεων
|
sign.maintainRatio=Εναλλαγή διατήρησης αναλογίας διαστάσεων
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Επιδιόρθωση
|
repair.title=Επιδιόρθωση
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repair
|
repair.title=Repair
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repair
|
repair.title=Repair
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Última página
|
|||||||
sign.next=Siguiente página
|
sign.next=Siguiente página
|
||||||
sign.previous=Página anterior
|
sign.previous=Página anterior
|
||||||
sign.maintainRatio=Activar/desactivar la relación de aspecto
|
sign.maintainRatio=Activar/desactivar la relación de aspecto
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Konpondu
|
repair.title=Konpondu
|
||||||
|
@ -860,7 +860,8 @@ sign.last=صفحه آخر
|
|||||||
sign.next=صفحه بعدی
|
sign.next=صفحه بعدی
|
||||||
sign.previous=صفحه قبلی
|
sign.previous=صفحه قبلی
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=تعمیر
|
repair.title=تعمیر
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Dernière page
|
|||||||
sign.next=Page suivante
|
sign.next=Page suivante
|
||||||
sign.previous=Page précédente
|
sign.previous=Page précédente
|
||||||
sign.maintainRatio=Conserver les proportions
|
sign.maintainRatio=Conserver les proportions
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Réparer
|
repair.title=Réparer
|
||||||
|
@ -860,7 +860,8 @@ sign.last=An leathanach deiridh
|
|||||||
sign.next=An chéad leathanach eile
|
sign.next=An chéad leathanach eile
|
||||||
sign.previous=Leathanach roimhe seo
|
sign.previous=Leathanach roimhe seo
|
||||||
sign.maintainRatio=Scoránaigh, coinnigh an cóimheas gné
|
sign.maintainRatio=Scoránaigh, coinnigh an cóimheas gné
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Deisiúchán
|
repair.title=Deisiúchán
|
||||||
|
@ -860,7 +860,8 @@ sign.last=अंतिम पृष्ठ
|
|||||||
sign.next=अगला पृष्ठ
|
sign.next=अगला पृष्ठ
|
||||||
sign.previous=पिछला पृष्ठ
|
sign.previous=पिछला पृष्ठ
|
||||||
sign.maintainRatio=आनुपातिक अनुपात बनाए रखें टॉगल करें
|
sign.maintainRatio=आनुपातिक अनुपात बनाए रखें टॉगल करें
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=मरम्मत
|
repair.title=मरम्मत
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Popravi
|
repair.title=Popravi
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Utolsó oldal
|
|||||||
sign.next=Következő oldal
|
sign.next=Következő oldal
|
||||||
sign.previous=Előző oldal
|
sign.previous=Előző oldal
|
||||||
sign.maintainRatio=Képarány fenntartása váltása
|
sign.maintainRatio=Képarány fenntartása váltása
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Javítás
|
repair.title=Javítás
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Perbaiki
|
repair.title=Perbaiki
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Ultima pagina
|
|||||||
sign.next=Prossima pagina
|
sign.next=Prossima pagina
|
||||||
sign.previous=Pagina precedente
|
sign.previous=Pagina precedente
|
||||||
sign.maintainRatio=Attiva il mantenimento delle proporzioni
|
sign.maintainRatio=Attiva il mantenimento delle proporzioni
|
||||||
|
sign.undo=Annulla
|
||||||
|
sign.redo=Rifare
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Ripara
|
repair.title=Ripara
|
||||||
|
@ -860,7 +860,8 @@ sign.last=最後のページ
|
|||||||
sign.next=次のページ
|
sign.next=次のページ
|
||||||
sign.previous=前のページ
|
sign.previous=前のページ
|
||||||
sign.maintainRatio=アスペクト比を維持を切替え
|
sign.maintainRatio=アスペクト比を維持を切替え
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=修復
|
repair.title=修復
|
||||||
|
@ -860,7 +860,8 @@ sign.last=마지막 페이지
|
|||||||
sign.next=다음 페이지
|
sign.next=다음 페이지
|
||||||
sign.previous=이전 페이지
|
sign.previous=이전 페이지
|
||||||
sign.maintainRatio=종횡비 유지 토글
|
sign.maintainRatio=종횡비 유지 토글
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=복구
|
repair.title=복구
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repareren
|
repair.title=Repareren
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparer
|
repair.title=Reparer
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Napraw
|
repair.title=Napraw
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Última página
|
|||||||
sign.next=Próxima página
|
sign.next=Próxima página
|
||||||
sign.previous=Página anterior
|
sign.previous=Página anterior
|
||||||
sign.maintainRatio=Habilitar manter proporção
|
sign.maintainRatio=Habilitar manter proporção
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Última página
|
|||||||
sign.next=Próxima página
|
sign.next=Próxima página
|
||||||
sign.previous=Página anterior
|
sign.previous=Página anterior
|
||||||
sign.maintainRatio=Alternar manter proporção
|
sign.maintainRatio=Alternar manter proporção
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repară
|
repair.title=Repară
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Последняя страница
|
|||||||
sign.next=Следующая страница
|
sign.next=Следующая страница
|
||||||
sign.previous=Предыдущая страница
|
sign.previous=Предыдущая страница
|
||||||
sign.maintainRatio=Переключить сохранение пропорций
|
sign.maintainRatio=Переключить сохранение пропорций
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Восстановление
|
repair.title=Восстановление
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Opraviť
|
repair.title=Opraviť
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Zadnja stran
|
|||||||
sign.next=Naslednja stran
|
sign.next=Naslednja stran
|
||||||
sign.previous=Prejšnja stran
|
sign.previous=Prejšnja stran
|
||||||
sign.maintainRatio=Preklopi ohranjanje razmerja stranic
|
sign.maintainRatio=Preklopi ohranjanje razmerja stranic
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Popravilo
|
repair.title=Popravilo
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Popravi
|
repair.title=Popravi
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Sista sidan
|
|||||||
sign.next=Nästa sida
|
sign.next=Nästa sida
|
||||||
sign.previous=Föregående sida
|
sign.previous=Föregående sida
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparera
|
repair.title=Reparera
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=ซ่อมแซม
|
repair.title=ซ่อมแซม
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Onar
|
repair.title=Onar
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Остання сторінка
|
|||||||
sign.next=Наступна сторінка
|
sign.next=Наступна сторінка
|
||||||
sign.previous=Попередня сторінка
|
sign.previous=Попередня сторінка
|
||||||
sign.maintainRatio=Переключити збереження пропорцій
|
sign.maintainRatio=Переключити збереження пропорцій
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Ремонт
|
repair.title=Ремонт
|
||||||
|
@ -860,7 +860,8 @@ sign.last=Last page
|
|||||||
sign.next=Next page
|
sign.next=Next page
|
||||||
sign.previous=Previous page
|
sign.previous=Previous page
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Sửa chữa
|
repair.title=Sửa chữa
|
||||||
|
@ -860,7 +860,8 @@ sign.last=ཤོག་ངོས་མཐའ་མ།
|
|||||||
sign.next=ཤོག་ངོས་རྗེས་མ།
|
sign.next=ཤོག་ངོས་རྗེས་མ།
|
||||||
sign.previous=ཤོག་ངོས་སྔོན་མ།
|
sign.previous=ཤོག་ངོས་སྔོན་མ།
|
||||||
sign.maintainRatio=བསྡུར་ཚད་རྒྱུན་འཁྱོངས་སྒོ་རྒྱག་པ།
|
sign.maintainRatio=བསྡུར་ཚད་རྒྱུན་འཁྱོངས་སྒོ་རྒྱག་པ།
|
||||||
|
sign.undo=Undo
|
||||||
|
sign.redo=Redo
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=བཟོ་བཅོས།
|
repair.title=བཟོ་བཅོས།
|
||||||
|
@ -860,7 +860,8 @@ sign.last=末页
|
|||||||
sign.next=下一页
|
sign.next=下一页
|
||||||
sign.previous=上一页
|
sign.previous=上一页
|
||||||
sign.maintainRatio=切换保持长宽比
|
sign.maintainRatio=切换保持长宽比
|
||||||
|
sign.undo=撤销
|
||||||
|
sign.redo=重做
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=修复
|
repair.title=修复
|
||||||
|
@ -860,7 +860,8 @@ sign.last=最後一頁
|
|||||||
sign.next=下一頁
|
sign.next=下一頁
|
||||||
sign.previous=上一頁
|
sign.previous=上一頁
|
||||||
sign.maintainRatio=切換維持長寬比
|
sign.maintainRatio=切換維持長寬比
|
||||||
|
sign.undo=撤销
|
||||||
|
sign.redo=重做
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=修復
|
repair.title=修復
|
||||||
|
@ -530,13 +530,6 @@
|
|||||||
"moduleLicense": "Apache-2.0",
|
"moduleLicense": "Apache-2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "commons-logging:commons-logging",
|
|
||||||
"moduleUrl": "https://commons.apache.org/proper/commons-logging/",
|
|
||||||
"moduleVersion": "1.3.4",
|
|
||||||
"moduleLicense": "Apache-2.0",
|
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "io.dropwizard.metrics:metrics-core",
|
"moduleName": "io.dropwizard.metrics:metrics-core",
|
||||||
"moduleVersion": "4.2.25",
|
"moduleVersion": "4.2.25",
|
||||||
@ -560,7 +553,7 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "io.micrometer:micrometer-core",
|
"moduleName": "io.micrometer:micrometer-core",
|
||||||
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
||||||
"moduleVersion": "1.14.4",
|
"moduleVersion": "1.14.5",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
|
@ -1,10 +1,48 @@
|
|||||||
const signaturePadCanvas = document.getElementById('drawing-pad-canvas');
|
const signaturePadCanvas = document.getElementById('drawing-pad-canvas');
|
||||||
|
const undoButton = document.getElementById("signature-undo-button");
|
||||||
|
const redoButton = document.getElementById("signature-redo-button");
|
||||||
const signaturePad = new SignaturePad(signaturePadCanvas, {
|
const signaturePad = new SignaturePad(signaturePadCanvas, {
|
||||||
minWidth: 1,
|
minWidth: 1,
|
||||||
maxWidth: 2,
|
maxWidth: 2,
|
||||||
penColor: 'black',
|
penColor: 'black',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let undoData = [];
|
||||||
|
|
||||||
|
signaturePad.addEventListener("endStroke", () => {
|
||||||
|
undoData = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("keydown", (event) => {
|
||||||
|
switch (true) {
|
||||||
|
case event.key === "z" && event.ctrlKey:
|
||||||
|
undoButton.click();
|
||||||
|
break;
|
||||||
|
case event.key === "y" && event.ctrlKey:
|
||||||
|
redoButton.click();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function undoDraw() {
|
||||||
|
const data = signaturePad.toData();
|
||||||
|
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
const removed = data.pop();
|
||||||
|
undoData.push(removed);
|
||||||
|
signaturePad.fromData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function redoDraw() {
|
||||||
|
|
||||||
|
if (undoData.length > 0) {
|
||||||
|
const data = signaturePad.toData();
|
||||||
|
data.push(undoData.pop());
|
||||||
|
signaturePad.fromData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addDraggableFromPad() {
|
function addDraggableFromPad() {
|
||||||
if (signaturePad.isEmpty()) return;
|
if (signaturePad.isEmpty()) return;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
@ -34,11 +34,15 @@
|
|||||||
<!-- Bootstrap -->
|
<!-- Bootstrap -->
|
||||||
<script th:src="@{'/js/thirdParty/popper.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/popper.min.js'}"></script>
|
||||||
<script th:src="@{'/js/thirdParty/bootstrap.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/bootstrap.min.js'}"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" th:href="@{'/css/bootstrap.min.css'}">
|
<link rel="stylesheet" th:href="@{'/css/bootstrap.min.css'}">
|
||||||
|
|
||||||
<!-- Bootstrap Icons -->
|
<!-- Bootstrap Icons -->
|
||||||
<link rel="stylesheet" th:href="@{'/css/bootstrap-icons.min.css'}">
|
<link rel="stylesheet" th:href="@{'/css/bootstrap-icons.min.css'}">
|
||||||
|
|
||||||
|
<!-- Pixel, doesn't collect any PII-->
|
||||||
|
<img referrerpolicy="no-referrer-when-downgrade" src="https://pixel.stirlingpdf.com/a.png?x-pxid=4f5fa02f-a065-4efb-bb2c-24509a4b6b92" style="position: absolute; visibility: hidden;"/>
|
||||||
|
|
||||||
<!-- Custom -->
|
<!-- Custom -->
|
||||||
<link rel="stylesheet" th:href="@{'/css/general.css'}">
|
<link rel="stylesheet" th:href="@{'/css/general.css'}">
|
||||||
<link rel="stylesheet" th:href="@{'/css/theme/theme.css'}">
|
<link rel="stylesheet" th:href="@{'/css/theme/theme.css'}">
|
||||||
|
@ -56,6 +56,10 @@
|
|||||||
th:text="#{sign.clear}"></button>
|
th:text="#{sign.clear}"></button>
|
||||||
<button id="save-signature" class="btn btn-outline-success mt-2" onclick="addDraggableFromPad()"
|
<button id="save-signature" class="btn btn-outline-success mt-2" onclick="addDraggableFromPad()"
|
||||||
th:text="#{sign.add}"></button>
|
th:text="#{sign.add}"></button>
|
||||||
|
<button id="signature-undo-button" class="btn btn-outline-secondary mt-2" th:text="#{sign.undo}"
|
||||||
|
onclick="undoDraw()"></button>
|
||||||
|
<button id="signature-redo-button" class="btn btn-outline-secondary mt-2" th:text="#{sign.redo}"
|
||||||
|
onclick="redoDraw()"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-container" th:title="#{sign.saved}" th:data-title="#{sign.saved}">
|
<div class="tab-container" th:title="#{sign.saved}" th:data-title="#{sign.saved}">
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
package stirling.software.SPDF;
|
package stirling.software.SPDF;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -16,22 +11,15 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
|||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import static java.nio.file.Files.createDirectories;
|
|
||||||
import static java.nio.file.Files.createFile;
|
|
||||||
import static java.nio.file.Files.delete;
|
|
||||||
import static java.nio.file.Files.exists;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
public class SPDFApplicationTest {
|
public class SPDFApplicationTest {
|
||||||
|
|
||||||
@Mock
|
@Mock private Environment env;
|
||||||
private Environment env;
|
|
||||||
|
|
||||||
@Mock
|
@Mock private ApplicationProperties applicationProperties;
|
||||||
private ApplicationProperties applicationProperties;
|
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks private SPDFApplication sPDFApplication;
|
||||||
private SPDFApplication sPDFApplication;
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@ -48,5 +36,4 @@ public class SPDFApplicationTest {
|
|||||||
public void testGetStaticPort() {
|
public void testGetStaticPort() {
|
||||||
assertEquals("8080", SPDFApplication.getStaticPort());
|
assertEquals("8080", SPDFApplication.getStaticPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,29 @@
|
|||||||
package stirling.software.SPDF.config.security;
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import static org.mockito.Mockito.mock;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class CustomLogoutSuccessHandlerTest {
|
class CustomLogoutSuccessHandlerTest {
|
||||||
|
|
||||||
@Mock
|
@Mock private ApplicationProperties applicationProperties;
|
||||||
private ApplicationProperties applicationProperties;
|
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks private CustomLogoutSuccessHandler customLogoutSuccessHandler;
|
||||||
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSuccessfulLogout() throws IOException {
|
void testSuccessfulLogout() throws IOException {
|
||||||
@ -44,7 +46,8 @@ class CustomLogoutSuccessHandlerTest {
|
|||||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||||
OAuth2AuthenticationToken oAuth2AuthenticationToken = mock(OAuth2AuthenticationToken.class);
|
OAuth2AuthenticationToken oAuth2AuthenticationToken = mock(OAuth2AuthenticationToken.class);
|
||||||
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
||||||
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
|
ApplicationProperties.Security.OAUTH2 oauth =
|
||||||
|
mock(ApplicationProperties.Security.OAUTH2.class);
|
||||||
|
|
||||||
when(response.isCommitted()).thenReturn(false);
|
when(response.isCommitted()).thenReturn(false);
|
||||||
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
||||||
@ -70,7 +73,8 @@ class CustomLogoutSuccessHandlerTest {
|
|||||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||||
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
||||||
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
||||||
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
|
ApplicationProperties.Security.OAUTH2 oauth =
|
||||||
|
mock(ApplicationProperties.Security.OAUTH2.class);
|
||||||
|
|
||||||
when(response.isCommitted()).thenReturn(false);
|
when(response.isCommitted()).thenReturn(false);
|
||||||
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
||||||
@ -100,7 +104,8 @@ class CustomLogoutSuccessHandlerTest {
|
|||||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||||
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
||||||
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
||||||
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
|
ApplicationProperties.Security.OAUTH2 oauth =
|
||||||
|
mock(ApplicationProperties.Security.OAUTH2.class);
|
||||||
|
|
||||||
when(response.isCommitted()).thenReturn(false);
|
when(response.isCommitted()).thenReturn(false);
|
||||||
when(request.getParameter(error)).thenReturn("true");
|
when(request.getParameter(error)).thenReturn("true");
|
||||||
@ -125,7 +130,8 @@ class CustomLogoutSuccessHandlerTest {
|
|||||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||||
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
||||||
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
||||||
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
|
ApplicationProperties.Security.OAUTH2 oauth =
|
||||||
|
mock(ApplicationProperties.Security.OAUTH2.class);
|
||||||
|
|
||||||
when(response.isCommitted()).thenReturn(false);
|
when(response.isCommitted()).thenReturn(false);
|
||||||
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
||||||
@ -151,7 +157,8 @@ class CustomLogoutSuccessHandlerTest {
|
|||||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||||
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
||||||
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
||||||
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
|
ApplicationProperties.Security.OAUTH2 oauth =
|
||||||
|
mock(ApplicationProperties.Security.OAUTH2.class);
|
||||||
|
|
||||||
when(response.isCommitted()).thenReturn(false);
|
when(response.isCommitted()).thenReturn(false);
|
||||||
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
||||||
@ -179,7 +186,8 @@ class CustomLogoutSuccessHandlerTest {
|
|||||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||||
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
||||||
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
||||||
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
|
ApplicationProperties.Security.OAUTH2 oauth =
|
||||||
|
mock(ApplicationProperties.Security.OAUTH2.class);
|
||||||
|
|
||||||
when(response.isCommitted()).thenReturn(false);
|
when(response.isCommitted()).thenReturn(false);
|
||||||
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
||||||
@ -209,7 +217,8 @@ class CustomLogoutSuccessHandlerTest {
|
|||||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||||
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
||||||
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
||||||
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
|
ApplicationProperties.Security.OAUTH2 oauth =
|
||||||
|
mock(ApplicationProperties.Security.OAUTH2.class);
|
||||||
|
|
||||||
when(response.isCommitted()).thenReturn(false);
|
when(response.isCommitted()).thenReturn(false);
|
||||||
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
||||||
@ -240,7 +249,8 @@ class CustomLogoutSuccessHandlerTest {
|
|||||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||||
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
|
||||||
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
|
||||||
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
|
ApplicationProperties.Security.OAUTH2 oauth =
|
||||||
|
mock(ApplicationProperties.Security.OAUTH2.class);
|
||||||
|
|
||||||
when(response.isCommitted()).thenReturn(false);
|
when(response.isCommitted()).thenReturn(false);
|
||||||
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
package stirling.software.SPDF.config.security.database;
|
package stirling.software.SPDF.config.security.database;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@ -8,18 +14,14 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class DatabaseConfigTest {
|
class DatabaseConfigTest {
|
||||||
|
|
||||||
@Mock
|
@Mock private ApplicationProperties applicationProperties;
|
||||||
private ApplicationProperties applicationProperties;
|
|
||||||
|
|
||||||
private DatabaseConfig databaseConfig;
|
private DatabaseConfig databaseConfig;
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user