Compare commits

...

15 Commits

Author SHA1 Message Date
Anthony Stirling
a9b4e1eaf1 Merge branch 'main' into testCleanups 2024-08-23 12:42:08 +02:00
Ludy
b23784f598 Fix: authentication ApiKey NullPointerException (#1744) 2024-08-23 12:10:58 +02:00
Ludy
90cbcde029 Fix: Missing multi-selection and Python validation (#1740)
Missing multi-selection and Python validation
2024-08-23 09:28:06 +01:00
Anthony Stirling
382edc01f8 Multiple flag fix (#1742)
* fix

* multiple file logic cleanup

* fix

---------

Co-authored-by: a <a>
2024-08-23 09:17:50 +01:00
a
3ff4a5e5b9 cleanups! 2024-08-23 00:05:56 +01:00
a
2bbbbf8e38 Merge branch 'main' of github.com:Stirling-Tools/Stirling-PDF 2024-08-23 00:02:25 +01:00
github-actions[bot]
dee912f075 📝 Update README: Translation Progress Table (#1734)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-08-22 21:47:37 +01:00
albanobattistella
faed367cde Update messages_it_IT.properties (#1732) 2024-08-22 11:54:55 +01:00
Anthony Stirling
788744c1be Update pull_request_template.md 2024-08-21 20:43:13 +01:00
github-actions[bot]
686b88d21d 📝 Update README: Translation Progress Table (#1731)
📝 Sync README
> Made via sync_files.yml

Co-authored-by: GitHub Action action@github.com <GitHub Action action@github.com>
2024-08-21 11:37:45 +01:00
Ludy
1a594b27ab Fix: introduces the verification of the python installation (#1730)
* Fix: introduces the verification of the python installation

* Update ExtractImageScansController.java

* Update CheckProgramInstall.java
2024-08-21 11:16:29 +01:00
Anthony Stirling
9f0088c839 Create release.yml 2024-08-20 22:56:15 +01:00
a
c778fa73ef Merge branch 'main' of git@github.com:Stirling-Tools/Stirling-PDF.git into main 2024-08-20 22:33:05 +01:00
a
89031246cf Merge branch 'main' of git@github.com:Stirling-Tools/Stirling-PDF.git into main 2024-08-16 13:21:39 +01:00
Anthony Stirling
e5cb9a28ac fix 2024-08-16 13:21:35 +01:00
129 changed files with 354 additions and 176 deletions

View File

@@ -10,9 +10,3 @@ Closes #(issue_number)
- [ ] I have performed a self-review of my own code - [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] My changes generate no new warnings - [ ] My changes generate no new warnings
## Contributor License Agreement
By submitting this pull request, I acknowledge and agree that my contributions will be included in Stirling-PDF and that they can be relicensed in the future under the MPL 2.0 (Mozilla Public License Version 2.0) license.
(This does not change the general open-source nature of Stirling-PDF, simply moving from one license to another license)

32
.github/release.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
changelog:
exclude:
labels:
- Documentation
- Test
- Github
categories:
- title: Bug Fixes
labels:
- Bug
- title: Enhancements
labels:
- enhancement
- title: Minor Enhancements
labels:
- Java
- Front End
- title: Docker Updates
labels:
- Docker
- title: Translation Changes
labels:
- Translation
- title: Other Changes
labels:
- "*"

View File

@@ -173,7 +173,7 @@ Stirling PDF currently supports 38!
| Basque (Euskara) (eu_ES) | ![60%](https://geps.dev/progress/60) | | Basque (Euskara) (eu_ES) | ![60%](https://geps.dev/progress/60) |
| Bulgarian (Български) (bg_BG) | ![92%](https://geps.dev/progress/92) | | Bulgarian (Български) (bg_BG) | ![92%](https://geps.dev/progress/92) |
| Catalan (Català) (ca_CA) | ![47%](https://geps.dev/progress/47) | | Catalan (Català) (ca_CA) | ![47%](https://geps.dev/progress/47) |
| Croatian (Hrvatski) (hr_HR) | ![93%](https://geps.dev/progress/93) | | Croatian (Hrvatski) (hr_HR) | ![92%](https://geps.dev/progress/92) |
| Czech (Česky) (cs_CZ) | ![88%](https://geps.dev/progress/88) | | Czech (Česky) (cs_CZ) | ![88%](https://geps.dev/progress/88) |
| Danish (Dansk) (da_DK) | ![9%](https://geps.dev/progress/9) | | Danish (Dansk) (da_DK) | ![9%](https://geps.dev/progress/9) |
| Dutch (Nederlands) (nl_NL) | ![94%](https://geps.dev/progress/94) | | Dutch (Nederlands) (nl_NL) | ![94%](https://geps.dev/progress/94) |
@@ -184,18 +184,18 @@ Stirling PDF currently supports 38!
| Greek (Ελληνικά) (el_GR) | ![80%](https://geps.dev/progress/80) | | Greek (Ελληνικά) (el_GR) | ![80%](https://geps.dev/progress/80) |
| Hindi (हिंदी) (hi_IN) | ![75%](https://geps.dev/progress/75) | | Hindi (हिंदी) (hi_IN) | ![75%](https://geps.dev/progress/75) |
| Hungarian (Magyar) (hu_HU) | ![74%](https://geps.dev/progress/74) | | Hungarian (Magyar) (hu_HU) | ![74%](https://geps.dev/progress/74) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![75%](https://geps.dev/progress/75) | | Indonesia (Bahasa Indonesia) (id_ID) | ![74%](https://geps.dev/progress/74) |
| Irish (Gaeilge) (ga_IE) | ![96%](https://geps.dev/progress/96) | | Irish (Gaeilge) (ga_IE) | ![96%](https://geps.dev/progress/96) |
| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) | | Italian (Italiano) (it_IT) | ![99%](https://geps.dev/progress/99) |
| Japanese (日本語) (ja_JP) | ![91%](https://geps.dev/progress/91) | | Japanese (日本語) (ja_JP) | ![90%](https://geps.dev/progress/90) |
| Korean (한국어) (ko_KR) | ![82%](https://geps.dev/progress/82) | | Korean (한국어) (ko_KR) | ![82%](https://geps.dev/progress/82) |
| Norwegian (Norsk) (no_NB) | ![96%](https://geps.dev/progress/96) | | Norwegian (Norsk) (no_NB) | ![96%](https://geps.dev/progress/96) |
| Polish (Polski) (pl_PL) | ![90%](https://geps.dev/progress/90) | | Polish (Polski) (pl_PL) | ![90%](https://geps.dev/progress/90) |
| Portuguese (Português) (pt_PT) | ![77%](https://geps.dev/progress/77) | | Portuguese (Português) (pt_PT) | ![76%](https://geps.dev/progress/76) |
| Portuguese Brazilian (Português) (pt_BR) | ![99%](https://geps.dev/progress/99) | | Portuguese Brazilian (Português) (pt_BR) | ![99%](https://geps.dev/progress/99) |
| Romanian (Română) (ro_RO) | ![38%](https://geps.dev/progress/38) | | Romanian (Română) (ro_RO) | ![38%](https://geps.dev/progress/38) |
| Russian (Русский) (ru_RU) | ![82%](https://geps.dev/progress/82) | | Russian (Русский) (ru_RU) | ![82%](https://geps.dev/progress/82) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![77%](https://geps.dev/progress/77) | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![76%](https://geps.dev/progress/76) |
| Simplified Chinese (简体中文) (zh_CN) | ![97%](https://geps.dev/progress/97) | | Simplified Chinese (简体中文) (zh_CN) | ![97%](https://geps.dev/progress/97) |
| Slovakian (Slovensky) (sk_SK) | ![90%](https://geps.dev/progress/90) | | Slovakian (Slovensky) (sk_SK) | ![90%](https://geps.dev/progress/90) |
| Spanish (Español) (es_ES) | ![96%](https://geps.dev/progress/96) | | Spanish (Español) (es_ES) | ![96%](https://geps.dev/progress/96) |

View File

@@ -7,6 +7,7 @@ plugins {
id "edu.sc.seis.launch4j" version "3.0.6" id "edu.sc.seis.launch4j" version "3.0.6"
id "com.diffplug.spotless" version "6.25.0" id "com.diffplug.spotless" version "6.25.0"
id "com.github.jk1.dependency-license-report" version "2.9" id "com.github.jk1.dependency-license-report" version "2.9"
//id "nebula.lint" version "19.0.3"
} }
import com.github.jk1.license.render.* import com.github.jk1.license.render.*
@@ -100,14 +101,20 @@ spotless {
} }
} }
//gradleLint {
// rules=['unused-dependency']
// }
tasks.wrapper { tasks.wrapper {
gradleVersion = "8.7" gradleVersion = "8.7"
} }
//tasks.withType(JavaCompile) {
// options.compilerArgs << "-Xlint:deprecation"
//}
configurations.all {
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
}
dependencies { dependencies {
//security updates //security updates
implementation "ch.qos.logback:logback-classic:$logbackVersion"
implementation "ch.qos.logback:logback-core:$logbackVersion"
implementation "org.springframework:spring-webmvc:6.1.9" implementation "org.springframework:spring-webmvc:6.1.9"
implementation("io.github.pixee:java-security-toolkit:1.2.0") implementation("io.github.pixee:java-security-toolkit:1.2.0")
@@ -116,36 +123,33 @@ dependencies {
implementation 'com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4' implementation 'com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4'
// Exclude Tomcat and include Jetty // Exclude Tomcat and include Jetty
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion") { implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
}
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") { if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE" runtimeOnly "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE"
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
//2.2.x requires rebuild of DB file.. need migration path //2.2.x requires rebuild of DB file.. need migration path
implementation "com.h2database:h2:2.1.214" runtimeOnly "com.h2database:h2:2.1.214"
// implementation "com.h2database:h2:2.2.224" // implementation "com.h2database:h2:2.2.224"
} }
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion" testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
// Batik // Batik
implementation "org.apache.xmlgraphics:batik-all:1.17"
// TwelveMonkeys // TwelveMonkeys
implementation "com.twelvemonkeys.imageio:imageio-batik:$imageioVersion" runtimeOnly "com.twelvemonkeys.imageio:imageio-batik:$imageioVersion"
implementation "com.twelvemonkeys.imageio:imageio-bmp:$imageioVersion" runtimeOnly "com.twelvemonkeys.imageio:imageio-bmp:$imageioVersion"
// implementation "com.twelvemonkeys.imageio:imageio-hdr:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-hdr:$imageioVersion"
// implementation "com.twelvemonkeys.imageio:imageio-icns:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-icns:$imageioVersion"
// implementation "com.twelvemonkeys.imageio:imageio-iff:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-iff:$imageioVersion"
implementation "com.twelvemonkeys.imageio:imageio-jpeg:$imageioVersion" runtimeOnly "com.twelvemonkeys.imageio:imageio-jpeg:$imageioVersion"
// implementation "com.twelvemonkeys.imageio:imageio-pcx:$imageioVersion@ // implementation "com.twelvemonkeys.imageio:imageio-pcx:$imageioVersion@
// implementation "com.twelvemonkeys.imageio:imageio-pict:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-pict:$imageioVersion"
// implementation "com.twelvemonkeys.imageio:imageio-pnm:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-pnm:$imageioVersion"
@@ -153,13 +157,12 @@ dependencies {
// implementation "com.twelvemonkeys.imageio:imageio-sgi:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-sgi:$imageioVersion"
// implementation "com.twelvemonkeys.imageio:imageio-tga:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-tga:$imageioVersion"
// implementation "com.twelvemonkeys.imageio:imageio-thumbsdb:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-thumbsdb:$imageioVersion"
implementation "com.twelvemonkeys.imageio:imageio-tiff:$imageioVersion" runtimeOnly "com.twelvemonkeys.imageio:imageio-tiff:$imageioVersion"
implementation "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion" runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
// implementation "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion" // implementation "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
implementation "commons-io:commons-io:2.16.1" implementation "commons-io:commons-io:2.16.1"
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0" implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0"
//general PDF //general PDF
// https://mvnrepository.com/artifact/com.opencsv/opencsv // https://mvnrepository.com/artifact/com.opencsv/opencsv
@@ -196,7 +199,7 @@ dependencies {
compileOnly "org.projectlombok:lombok:$lombokVersion" compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion" annotationProcessor "org.projectlombok:lombok:$lombokVersion"
testImplementation 'org.mockito:mockito-inline:5.2.0' testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
} }
tasks.withType(JavaCompile).configureEach { tasks.withType(JavaCompile).configureEach {

View File

@@ -65,6 +65,7 @@ public class SPdfApplication {
public static void main(String[] args) throws IOException, InterruptedException { public static void main(String[] args) throws IOException, InterruptedException {
SpringApplication app = new SpringApplication(SPdfApplication.class); SpringApplication app = new SpringApplication(SPdfApplication.class);
app.setAdditionalProfiles("default");
app.addInitializers(new ConfigInitializer()); app.addInitializers(new ConfigInitializer());
Map<String, String> propertyFiles = new HashMap<>(); Map<String, String> propertyFiles = new HashMap<>();

View File

@@ -10,7 +10,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -150,8 +149,7 @@ public class SecurityConfiguration {
}) })
.permitAll() .permitAll()
.anyRequest() .anyRequest()
.authenticated()) .authenticated());
.authenticationProvider(authenticationProvider());
// Handle OAUTH2 Logins // Handle OAUTH2 Logins
if (applicationProperties.getSecurity().getOAUTH2() != null if (applicationProperties.getSecurity().getOAUTH2() != null
@@ -379,14 +377,6 @@ public class SecurityConfiguration {
return new IPRateLimitingFilter(maxRequestsPerIp, maxRequestsPerIp); return new IPRateLimitingFilter(maxRequestsPerIp, maxRequestsPerIp);
} }
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean @Bean
public PersistentTokenRepository persistentTokenRepository() { public PersistentTokenRepository persistentTokenRepository() {
return new JPATokenRepositoryImpl(); return new JPATokenRepositoryImpl();

View File

@@ -58,7 +58,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
try { try {
// Use API key to authenticate. This requires you to have an authentication // Use API key to authenticate. This requires you to have an authentication
// provider for API keys. // provider for API keys.
Optional<User> user = userService.loadUserByApiKey(apiKey); Optional<User> user = userService.getUserByApiKey(apiKey);
if (!user.isPresent()) { if (!user.isPresent()) {
response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter().write("Invalid API Key."); response.getWriter().write("Invalid API Key.");

View File

@@ -22,7 +22,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.DatabaseBackupInterface; import stirling.software.SPDF.config.DatabaseBackupInterface;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface; import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;

View File

@@ -7,7 +7,6 @@ import java.net.URLConnection;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
@@ -17,7 +16,6 @@ import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.ImageType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@@ -32,6 +30,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
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.utils.CheckProgramInstall;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
@@ -82,7 +81,10 @@ public class ConvertImgPDFController {
if (result == null || result.length == 0) { if (result == null || result.length == 0) {
logger.error("resultant bytes for {} is null, error converting ", filename); logger.error("resultant bytes for {} is null, error converting ", filename);
} }
if (imageFormat.equalsIgnoreCase("webp")) { if (imageFormat.equalsIgnoreCase("webp") && !CheckProgramInstall.isPythonAvailable()) {
throw new IOException("Python is not installed. Required for WebP conversion.");
} else if (imageFormat.equalsIgnoreCase("webp")
&& CheckProgramInstall.isPythonAvailable()) {
// Write the output stream to a temp file // Write the output stream to a temp file
Path tempFile = Files.createTempFile("temp_png", ".png"); Path tempFile = Files.createTempFile("temp_png", ".png");
try (FileOutputStream fos = new FileOutputStream(tempFile.toFile())) { try (FileOutputStream fos = new FileOutputStream(tempFile.toFile())) {
@@ -90,21 +92,13 @@ public class ConvertImgPDFController {
fos.flush(); fos.flush();
} }
String pythonVersion = "python3"; String pythonVersion = CheckProgramInstall.getAvailablePythonCommand();
try {
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
.runCommandWithOutputHandling(Arrays.asList("python3", "--version"));
} catch (IOException e) {
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
.runCommandWithOutputHandling(Arrays.asList("python", "--version"));
pythonVersion = "python";
}
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
command.add(pythonVersion); command.add(pythonVersion);
command.add("./scripts/png_to_webp.py"); // Python script to handle the conversion command.add("./scripts/png_to_webp.py"); // Python script to handle the conversion
// Create a temporary directory for the output WebP files // Create a temporary directory for the output WebP files
Path tempOutputDir = Files.createTempDirectory("webp_output"); Path tempOutputDir = Files.createTempDirectory("webp_output");
if (singleImage) { if (singleImage) {
// Run the Python script to convert PNG to WebP // Run the Python script to convert PNG to WebP

View File

@@ -32,6 +32,7 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest; import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
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;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;
@@ -76,6 +77,11 @@ public class ExtractImageScansController {
Path tempZipFile = null; Path tempZipFile = null;
List<Path> tempDirs = new ArrayList<>(); List<Path> tempDirs = new ArrayList<>();
if (!CheckProgramInstall.isPythonAvailable()) {
throw new IOException("Python is not installed.");
}
String pythonVersion = CheckProgramInstall.getAvailablePythonCommand();
try { try {
// Check if input file is a PDF // Check if input file is a PDF
if ("pdf".equalsIgnoreCase(extension)) { if ("pdf".equalsIgnoreCase(extension)) {
@@ -117,7 +123,7 @@ public class ExtractImageScansController {
List<String> command = List<String> command =
new ArrayList<>( new ArrayList<>(
Arrays.asList( Arrays.asList(
"python3", pythonVersion,
"./scripts/split_photos.py", "./scripts/split_photos.py",
images.get(i), images.get(i),
tempDir.toString(), tempDir.toString(),

View File

@@ -140,9 +140,9 @@ public class ExtractImagesController {
Set<Integer> processedImages, Set<Integer> processedImages,
ZipOutputStream zos) ZipOutputStream zos)
throws IOException { throws IOException {
if(page.getResources() == null || page.getResources().getXObjectNames() == null) { if (page.getResources() == null || page.getResources().getXObjectNames() == null) {
return; return;
} }
for (COSName name : page.getResources().getXObjectNames()) { for (COSName name : page.getResources().getXObjectNames()) {
if (page.getResources().isImageXObject(name)) { if (page.getResources().isImageXObject(name)) {
PDImageXObject image = (PDImageXObject) page.getResources().getXObject(name); PDImageXObject image = (PDImageXObject) page.getResources().getXObject(name);

View File

@@ -43,7 +43,7 @@ public class ApiDocService {
Map<String, List<String>> outputToFileTypes = new HashMap<>(); Map<String, List<String>> outputToFileTypes = new HashMap<>();
public List getExtensionTypes(boolean output, String operationName) { public List<String> getExtensionTypes(boolean output, String operationName) {
if (outputToFileTypes.size() == 0) { if (outputToFileTypes.size() == 0) {
outputToFileTypes.put("PDF", Arrays.asList("pdf")); outputToFileTypes.put("PDF", Arrays.asList("pdf"));
outputToFileTypes.put( outputToFileTypes.put(

View File

@@ -9,6 +9,8 @@ import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.utils.CheckProgramInstall;
@Controller @Controller
@Tag(name = "Convert", description = "Convert APIs") @Tag(name = "Convert", description = "Convert APIs")
public class ConverterWebController { public class ConverterWebController {
@@ -69,6 +71,8 @@ public class ConverterWebController {
@GetMapping("/pdf-to-img") @GetMapping("/pdf-to-img")
@Hidden @Hidden
public String pdfToimgForm(Model model) { public String pdfToimgForm(Model model) {
boolean isPython = CheckProgramInstall.isPythonAvailable();
model.addAttribute("isPython", isPython);
model.addAttribute("currentPage", "pdf-to-img"); model.addAttribute("currentPage", "pdf-to-img");
return "convert/pdf-to-img"; return "convert/pdf-to-img";
} }

View File

@@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.CheckProgramInstall;
@Controller @Controller
@Tag(name = "Misc", description = "Miscellaneous APIs") @Tag(name = "Misc", description = "Miscellaneous APIs")
@@ -34,6 +35,8 @@ public class OtherWebController {
@Hidden @Hidden
public ModelAndView extractImageScansForm() { public ModelAndView extractImageScansForm() {
ModelAndView modelAndView = new ModelAndView("misc/extract-image-scans"); ModelAndView modelAndView = new ModelAndView("misc/extract-image-scans");
boolean isPython = CheckProgramInstall.isPythonAvailable();
modelAndView.addObject("isPython", isPython);
modelAndView.addObject("currentPage", "extract-image-scans"); modelAndView.addObject("currentPage", "extract-image-scans");
return modelAndView; return modelAndView;
} }

View File

@@ -9,6 +9,8 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode @EqualsAndHashCode
public class UrlToPdfRequest { public class UrlToPdfRequest {
@Schema(description = "The input URL to be converted to a PDF file", required = true) @Schema(
description = "The input URL to be converted to a PDF file",
requiredMode = Schema.RequiredMode.REQUIRED)
private String urlInput; private String urlInput;
} }

View File

@@ -10,6 +10,6 @@ import stirling.software.SPDF.model.api.PDFWithPageNums;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class ContainsTextRequest extends PDFWithPageNums { public class ContainsTextRequest extends PDFWithPageNums {
@Schema(description = "The text to check for", required = true) @Schema(description = "The text to check for", requiredMode = Schema.RequiredMode.REQUIRED)
private String text; private String text;
} }

View File

@@ -10,6 +10,6 @@ import stirling.software.SPDF.model.api.PDFComparison;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class FileSizeRequest extends PDFComparison { public class FileSizeRequest extends PDFComparison {
@Schema(description = "File Size", required = true) @Schema(description = "File Size", requiredMode = Schema.RequiredMode.REQUIRED)
private String fileSize; private String fileSize;
} }

View File

@@ -10,6 +10,6 @@ import stirling.software.SPDF.model.api.PDFComparison;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PageRotationRequest extends PDFComparison { public class PageRotationRequest extends PDFComparison {
@Schema(description = "Rotation in degrees", required = true) @Schema(description = "Rotation in degrees", requiredMode = Schema.RequiredMode.REQUIRED)
private int rotation; private int rotation;
} }

View File

@@ -10,6 +10,6 @@ import stirling.software.SPDF.model.api.PDFComparison;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PageSizeRequest extends PDFComparison { public class PageSizeRequest extends PDFComparison {
@Schema(description = "Standard Page Size", required = true) @Schema(description = "Standard Page Size", requiredMode = Schema.RequiredMode.REQUIRED)
private String standardPageSize; private String standardPageSize;
} }

View File

@@ -20,13 +20,13 @@ public class OverlayPdfsRequest extends PDFFile {
@Schema( @Schema(
description = description =
"The mode of overlaying: 'SequentialOverlay' for sequential application, 'InterleavedOverlay' for round-robin application, 'FixedRepeatOverlay' for fixed repetition based on provided counts", "The mode of overlaying: 'SequentialOverlay' for sequential application, 'InterleavedOverlay' for round-robin application, 'FixedRepeatOverlay' for fixed repetition based on provided counts",
required = true) requiredMode = Schema.RequiredMode.REQUIRED)
private String overlayMode; private String overlayMode;
@Schema( @Schema(
description = description =
"An array of integers specifying the number of times each corresponding overlay file should be applied in the 'FixedRepeatOverlay' mode. This should match the length of the overlayFiles array.", "An array of integers specifying the number of times each corresponding overlay file should be applied in the 'FixedRepeatOverlay' mode. This should match the length of the overlayFiles array.",
required = false) requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private int[] counts; private int[] counts;
@Schema(description = "Overlay position 0 is Foregound, 1 is Background") @Schema(description = "Overlay position 0 is Foregound, 1 is Background")

View File

@@ -13,14 +13,14 @@ public class SplitPdfBySizeOrCountRequest extends PDFFile {
@Schema( @Schema(
description = description =
"Determines the type of split: 0 for size, 1 for page count, 2 for document count", "Determines the type of split: 0 for size, 1 for page count, 2 for document count",
required = false, requiredMode = Schema.RequiredMode.NOT_REQUIRED,
defaultValue = "0") defaultValue = "0")
private int splitType; private int splitType;
@Schema( @Schema(
description = description =
"Value for split: size in MB (e.g., '10MB') or number of pages (e.g., '5')", "Value for split: size in MB (e.g., '10MB') or number of pages (e.g., '5')",
required = false, requiredMode = Schema.RequiredMode.NOT_REQUIRED,
defaultValue = "10MB") defaultValue = "10MB")
private String splitValue; private String splitValue;
} }

View File

@@ -15,7 +15,7 @@ public class AddStampRequest extends PDFWithPageNums {
@Schema( @Schema(
description = "The stamp type (text or image)", description = "The stamp type (text or image)",
allowableValues = {"text", "image"}, allowableValues = {"text", "image"},
required = true) requiredMode = Schema.RequiredMode.REQUIRED)
private String stampType; private String stampType;
@Schema(description = "The stamp text") @Schema(description = "The stamp text")

View File

@@ -13,7 +13,7 @@ public class AutoSplitPdfRequest extends PDFFile {
@Schema( @Schema(
description = description =
"Flag indicating if the duplex mode is active, where the page after the divider also gets removed.", "Flag indicating if the duplex mode is active, where the page after the divider also gets removed.",
required = false, requiredMode = Schema.RequiredMode.NOT_REQUIRED,
defaultValue = "false") defaultValue = "false")
private boolean duplexMode; private boolean duplexMode;
} }

View File

@@ -13,7 +13,7 @@ public class ExtractHeaderRequest extends PDFFile {
@Schema( @Schema(
description = description =
"Flag indicating whether to use the first text as a fallback if no suitable title is found. Defaults to false.", "Flag indicating whether to use the first text as a fallback if no suitable title is found. Defaults to false.",
required = false, requiredMode = Schema.RequiredMode.NOT_REQUIRED,
defaultValue = "false") defaultValue = "false")
private boolean useFirstTextAsFallback; private boolean useFirstTextAsFallback;
} }

View File

@@ -10,7 +10,9 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode @EqualsAndHashCode
public class ExtractImageScansRequest { public class ExtractImageScansRequest {
@Schema(description = "The input file containing image scans", required = true) @Schema(
description = "The input file containing image scans",
requiredMode = Schema.RequiredMode.REQUIRED)
private MultipartFile fileInput; private MultipartFile fileInput;
@Schema( @Schema(

View File

@@ -10,6 +10,8 @@ import stirling.software.SPDF.model.api.PDFFile;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PrintFileRequest extends PDFFile { public class PrintFileRequest extends PDFFile {
@Schema(description = "Name of printer to match against", required = true) @Schema(
description = "Name of printer to match against",
requiredMode = Schema.RequiredMode.REQUIRED)
private String printerName; private String printerName;
} }

View File

@@ -15,7 +15,7 @@ public class AddWatermarkRequest extends PDFFile {
@Schema( @Schema(
description = "The watermark type (text or image)", description = "The watermark type (text or image)",
allowableValues = {"text", "image"}, allowableValues = {"text", "image"},
required = true) requiredMode = Schema.RequiredMode.REQUIRED)
private String watermarkType; private String watermarkType;
@Schema(description = "The watermark text") @Schema(description = "The watermark text")

View File

@@ -10,6 +10,8 @@ import stirling.software.SPDF.model.api.PDFFile;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PDFPasswordRequest extends PDFFile { public class PDFPasswordRequest extends PDFFile {
@Schema(description = "The password of the PDF file", required = true) @Schema(
description = "The password of the PDF file",
requiredMode = Schema.RequiredMode.REQUIRED)
private String password; private String password;
} }

View File

@@ -10,7 +10,10 @@ import stirling.software.SPDF.model.api.PDFFile;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class RedactPdfRequest extends PDFFile { public class RedactPdfRequest extends PDFFile {
@Schema(description = "List of text to redact from the PDF", type = "string", required = true) @Schema(
description = "List of text to redact from the PDF",
type = "string",
requiredMode = Schema.RequiredMode.REQUIRED)
private String listOfText; private String listOfText;
@Schema(description = "Whether to use regex for the listOfText", defaultValue = "false") @Schema(description = "Whether to use regex for the listOfText", defaultValue = "false")

View File

@@ -0,0 +1,59 @@
package stirling.software.SPDF.utils;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
public class CheckProgramInstall {
private static final List<String> PYTHON_COMMANDS = Arrays.asList("python3", "python");
private static boolean pythonAvailableChecked = false;
private static String availablePythonCommand = null;
/**
* Checks which Python command is available and returns it.
*
* @return The available Python command ("python3" or "python"), or null if neither is
* available.
*/
public static String getAvailablePythonCommand() {
if (!pythonAvailableChecked) {
availablePythonCommand =
PYTHON_COMMANDS.stream()
.filter(CheckProgramInstall::checkPythonVersion)
.findFirst()
.orElse(null);
pythonAvailableChecked = true;
}
return availablePythonCommand;
}
/**
* Checks if the specified command is available by running the command with --version.
*
* @param pythonCommand The Python command to check.
* @return true if the command is available, false otherwise.
*/
private static boolean checkPythonVersion(String pythonCommand) {
try {
ProcessExecutorResult result =
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
.runCommandWithOutputHandling(
Arrays.asList(pythonCommand, "--version"));
return true; // Command succeeded, Python is available
} catch (IOException | InterruptedException e) {
return false; // Command failed, Python is not available
}
}
/**
* Checks if any Python command is available.
*
* @return true if any Python command is available, false otherwise.
*/
public static boolean isPythonAvailable() {
return getAvailablePythonCommand() != null;
}
}

View File

@@ -4,7 +4,10 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -13,8 +16,6 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.net.URL;
import java.net.HttpURLConnection;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -73,12 +74,11 @@ public class GeneralUtils {
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
return false; return false;
} }
}
}
public static boolean isURLReachable(String urlStr) { public static boolean isURLReachable(String urlStr) {
try { try {
URL url = new URL(urlStr); URL url = URI.create(urlStr).toURL();
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD"); connection.setRequestMethod("HEAD");
int responseCode = connection.getResponseCode(); int responseCode = connection.getResponseCode();
@@ -112,16 +112,19 @@ public class GeneralUtils {
sizeStr = sizeStr.replace(",", ".").replace(" ", ""); sizeStr = sizeStr.replace(",", ".").replace(" ", "");
try { try {
if (sizeStr.endsWith("KB")) { if (sizeStr.endsWith("KB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024); return (long)
(Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024);
} else if (sizeStr.endsWith("MB")) { } else if (sizeStr.endsWith("MB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) return (long)
* 1024 (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2))
* 1024); * 1024
* 1024);
} else if (sizeStr.endsWith("GB")) { } else if (sizeStr.endsWith("GB")) {
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) return (long)
* 1024 (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2))
* 1024 * 1024
* 1024); * 1024
* 1024);
} else if (sizeStr.endsWith("B")) { } else if (sizeStr.endsWith("B")) {
return Long.parseLong(sizeStr.substring(0, sizeStr.length() - 1)); return Long.parseLong(sizeStr.substring(0, sizeStr.length() - 1));
} else { } else {
@@ -191,8 +194,7 @@ public class GeneralUtils {
// Check if the result is null or not within bounds // Check if the result is null or not within bounds
if (result == null || result <= 0 || result.intValue() > maxValue) { if (result == null || result <= 0 || result.intValue() > maxValue) {
if (n != 0) if (n != 0) break;
break;
} else { } else {
results.add(result.intValue()); results.add(result.intValue());
} }

View File

@@ -1,5 +1,11 @@
multipart.enabled=true multipart.enabled=true
logging.level.org.springframework=WARN
logging.level.org.hibernate=WARN
logging.level.org.eclipse.jetty=WARN
logging.level.com.zaxxer.hikari=WARN
spring.jpa.open-in-view=false
server.forward-headers-strategy=NATIVE server.forward-headers-strategy=NATIVE
@@ -24,10 +30,8 @@ spring.devtools.livereload.enabled=true
spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.encoding=UTF-8
server.connection-timeout=${SYSTEM_CONNECTIONTIMEOUTMINUTES:20m}
spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
spring.resources.static-locations=file:customFiles/static/ spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/ #spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
#spring.thymeleaf.cache=false #spring.thymeleaf.cache=false

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=الحد الأدنى لمنطقة المحيط:
ScannerImageSplit.selectText.8=تعيين الحد الأدنى لمنطقة المحيط للصورة ScannerImageSplit.selectText.8=تعيين الحد الأدنى لمنطقة المحيط للصورة
ScannerImageSplit.selectText.9=حجم الحدود: ScannerImageSplit.selectText.9=حجم الحدود:
ScannerImageSplit.selectText.10=يضبط حجم الحدود المضافة والمزالة لمنع الحدود البيضاء في الإخراج (الافتراضي: 1). ScannerImageSplit.selectText.10=يضبط حجم الحدود المضافة والمزالة لمنع الحدود البيضاء في الإخراج (الافتراضي: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=اللون
pdfToImage.grey=تدرج الرمادي pdfToImage.grey=تدرج الرمادي
pdfToImage.blackwhite=أبيض وأسود (قد يفقد البيانات!) pdfToImage.blackwhite=أبيض وأسود (قد يفقد البيانات!)
pdfToImage.submit=تحول pdfToImage.submit=تحول
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Минимална контурна площ:
ScannerImageSplit.selectText.8=Задава минималния праг на контурната площ за изображение ScannerImageSplit.selectText.8=Задава минималния праг на контурната площ за изображение
ScannerImageSplit.selectText.9=Размер на рамката: ScannerImageSplit.selectText.9=Размер на рамката:
ScannerImageSplit.selectText.10=Задава размера на добавената и премахната граница, за да предотврати бели граници към изхода (по подразбиране: 1). ScannerImageSplit.selectText.10=Задава размера на добавената и премахната граница, за да предотврати бели граници към изхода (по подразбиране: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Цвят
pdfToImage.grey=Скала на сивото pdfToImage.grey=Скала на сивото
pdfToImage.blackwhite=Черно и бяло (може да загубите данни!) pdfToImage.blackwhite=Черно и бяло (може да загубите данни!)
pdfToImage.submit=Преобразуване pdfToImage.submit=Преобразуване
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Àrea de contorn mínima:
ScannerImageSplit.selectText.8=Estableix el llindar mínim de l'àrea de contorn per a una foto ScannerImageSplit.selectText.8=Estableix el llindar mínim de l'àrea de contorn per a una foto
ScannerImageSplit.selectText.9=Mida Vora: ScannerImageSplit.selectText.9=Mida Vora:
ScannerImageSplit.selectText.10=Estableix la mida de la vora afegida i eliminada per evitar vores blanques a la sortida (per defecte: 1). ScannerImageSplit.selectText.10=Estableix la mida de la vora afegida i eliminada per evitar vores blanques a la sortida (per defecte: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Color
pdfToImage.grey=Escala de Grisos pdfToImage.grey=Escala de Grisos
pdfToImage.blackwhite=Blanc i Negre (Pot perdre dades!) pdfToImage.blackwhite=Blanc i Negre (Pot perdre dades!)
pdfToImage.submit=Converteix pdfToImage.submit=Converteix
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimální plocha kontury:
ScannerImageSplit.selectText.8=Nastaví minimální plošný práh kontury pro fotografii ScannerImageSplit.selectText.8=Nastaví minimální plošný práh kontury pro fotografii
ScannerImageSplit.selectText.9=Velikost okraje: ScannerImageSplit.selectText.9=Velikost okraje:
ScannerImageSplit.selectText.10=Nastaví velikost okraje přidaného a odebraného k zabránění bílých ohraničení ve výstupu (výchozí: 1). ScannerImageSplit.selectText.10=Nastaví velikost okraje přidaného a odebraného k zabránění bílých ohraničení ve výstupu (výchozí: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Barevný
pdfToImage.grey=Stupně šedi pdfToImage.grey=Stupně šedi
pdfToImage.blackwhite=Černobílý (Může dojít k ztrátě dat!) pdfToImage.blackwhite=Černobílý (Může dojít k ztrátě dat!)
pdfToImage.submit=Převést pdfToImage.submit=Převést
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimum Contour Area:
ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo
ScannerImageSplit.selectText.9=Border Size: ScannerImageSplit.selectText.9=Border Size:
ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1). ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Colour
pdfToImage.grey=Greyscale pdfToImage.grey=Greyscale
pdfToImage.blackwhite=Black and White (May lose data!) pdfToImage.blackwhite=Black and White (May lose data!)
pdfToImage.submit=Convert pdfToImage.submit=Convert
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimaler Konturbereich:
ScannerImageSplit.selectText.8=Legt den minimalen Konturbereichsschwellenwert für ein Foto fest ScannerImageSplit.selectText.8=Legt den minimalen Konturbereichsschwellenwert für ein Foto fest
ScannerImageSplit.selectText.9=Randgröße: ScannerImageSplit.selectText.9=Randgröße:
ScannerImageSplit.selectText.10=Legt die Größe des hinzugefügten und entfernten Randes fest, um weiße Ränder in der Ausgabe zu verhindern (Standard: 1). ScannerImageSplit.selectText.10=Legt die Größe des hinzugefügten und entfernten Randes fest, um weiße Ränder in der Ausgabe zu verhindern (Standard: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Farbe
pdfToImage.grey=Graustufen pdfToImage.grey=Graustufen
pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!) pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!)
pdfToImage.submit=Umwandeln pdfToImage.submit=Umwandeln
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Ελάχιστη επιφάνεια περιγρ
ScannerImageSplit.selectText.8=Ρυθμίζει το ελάχιστο όριο περιγράμματος για μια φωτογραφία ScannerImageSplit.selectText.8=Ρυθμίζει το ελάχιστο όριο περιγράμματος για μια φωτογραφία
ScannerImageSplit.selectText.9=Μέγεθος περιγράμματος: ScannerImageSplit.selectText.9=Μέγεθος περιγράμματος:
ScannerImageSplit.selectText.10=Ορίζει το μέγεθος του περιγράμματος που προστίθεται και αφαιρείται για να αποτρέπονται λευκά περιγράμματα στην έξοδο (προεπιλογή: 1). ScannerImageSplit.selectText.10=Ορίζει το μέγεθος του περιγράμματος που προστίθεται και αφαιρείται για να αποτρέπονται λευκά περιγράμματα στην έξοδο (προεπιλογή: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Χρώμα
pdfToImage.grey=Κλίμακα του γκρι pdfToImage.grey=Κλίμακα του γκρι
pdfToImage.blackwhite=Ασπρόμαυρο (Μπορεί να χαθούν δεδομένα!) pdfToImage.blackwhite=Ασπρόμαυρο (Μπορεί να χαθούν δεδομένα!)
pdfToImage.submit=Μετατροπή pdfToImage.submit=Μετατροπή
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimum Contour Area:
ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo
ScannerImageSplit.selectText.9=Border Size: ScannerImageSplit.selectText.9=Border Size:
ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1). ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Colour
pdfToImage.grey=Greyscale pdfToImage.grey=Greyscale
pdfToImage.blackwhite=Black and White (May lose data!) pdfToImage.blackwhite=Black and White (May lose data!)
pdfToImage.submit=Convert pdfToImage.submit=Convert
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimum Contour Area:
ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo ScannerImageSplit.selectText.8=Sets the minimum contour area threshold for a photo
ScannerImageSplit.selectText.9=Border Size: ScannerImageSplit.selectText.9=Border Size:
ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1). ScannerImageSplit.selectText.10=Sets the size of the border added and removed to prevent white borders in the output (default: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Color
pdfToImage.grey=Grayscale pdfToImage.grey=Grayscale
pdfToImage.blackwhite=Black and White (May lose data!) pdfToImage.blackwhite=Black and White (May lose data!)
pdfToImage.submit=Convert pdfToImage.submit=Convert
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Área mínima de contorno:
ScannerImageSplit.selectText.8=Establecer el umbral mínimo del área de contorno para una foto ScannerImageSplit.selectText.8=Establecer el umbral mínimo del área de contorno para una foto
ScannerImageSplit.selectText.9=Tamaño del borde: ScannerImageSplit.selectText.9=Tamaño del borde:
ScannerImageSplit.selectText.10=Establece el tamaño del borde agregado y eliminado para evitar bordes blancos en la salida (predeterminado: 1). ScannerImageSplit.selectText.10=Establece el tamaño del borde agregado y eliminado para evitar bordes blancos en la salida (predeterminado: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Color
pdfToImage.grey=Escala de grises pdfToImage.grey=Escala de grises
pdfToImage.blackwhite=Blanco y Negro (¡Puede perder datos!) pdfToImage.blackwhite=Blanco y Negro (¡Puede perder datos!)
pdfToImage.submit=Convertir pdfToImage.submit=Convertir
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Inguruko area gutxienekoa:
ScannerImageSplit.selectText.8=Ezarri inguruko arearen gutxieneko balioa argazki batentzat ScannerImageSplit.selectText.8=Ezarri inguruko arearen gutxieneko balioa argazki batentzat
ScannerImageSplit.selectText.9=Ertzaren tamaina: ScannerImageSplit.selectText.9=Ertzaren tamaina:
ScannerImageSplit.selectText.10=Ezarri gehitutako eta ezabatutako ertzaren tamaina irteeran ertz zuriak saihesteko (lehenetsia: 1). ScannerImageSplit.selectText.10=Ezarri gehitutako eta ezabatutako ertzaren tamaina irteeran ertz zuriak saihesteko (lehenetsia: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Kolorea
pdfToImage.grey=Gris-eskala pdfToImage.grey=Gris-eskala
pdfToImage.blackwhite=Zuria eta Beltza (Datuak galdu ditzake!) pdfToImage.blackwhite=Zuria eta Beltza (Datuak galdu ditzake!)
pdfToImage.submit=Bihurtu pdfToImage.submit=Bihurtu
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Surface de contour minimale
ScannerImageSplit.selectText.8=Définit la surface de contour minimale pour une photo (par défaut : 500). ScannerImageSplit.selectText.8=Définit la surface de contour minimale pour une photo (par défaut : 500).
ScannerImageSplit.selectText.9=Taille de la bordure ScannerImageSplit.selectText.9=Taille de la bordure
ScannerImageSplit.selectText.10=Définit la taille de la bordure ajoutée et supprimée pour éviter les bordures blanches dans la sortie (par défaut : 1). ScannerImageSplit.selectText.10=Définit la taille de la bordure ajoutée et supprimée pour éviter les bordures blanches dans la sortie (par défaut : 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Couleur
pdfToImage.grey=Niveaux de gris pdfToImage.grey=Niveaux de gris
pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données !) pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données !)
pdfToImage.submit=Convertir pdfToImage.submit=Convertir
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Íos-Limistéar Comhrianta:
ScannerImageSplit.selectText.8=Socraíonn sé an tairseach íosta achar comhrianta le haghaidh grianghraf ScannerImageSplit.selectText.8=Socraíonn sé an tairseach íosta achar comhrianta le haghaidh grianghraf
ScannerImageSplit.selectText.9=Méid na Teorann: ScannerImageSplit.selectText.9=Méid na Teorann:
ScannerImageSplit.selectText.10=Socraíonn sé méid na teorann a chuirtear leis agus a bhaintear chun teorainneacha bán a chosc san aschur (réamhshocraithe: 1). ScannerImageSplit.selectText.10=Socraíonn sé méid na teorann a chuirtear leis agus a bhaintear chun teorainneacha bán a chosc san aschur (réamhshocraithe: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Dath
pdfToImage.grey=Scála Liath pdfToImage.grey=Scála Liath
pdfToImage.blackwhite=Dubh agus Bán (Dfhéadfadh sonraí a chailleadh!) pdfToImage.blackwhite=Dubh agus Bán (Dfhéadfadh sonraí a chailleadh!)
pdfToImage.submit=Tiontaigh pdfToImage.submit=Tiontaigh
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=न्यूनतम कंटोर क्ष
ScannerImageSplit.selectText.8=फोटो के लिए न्यूनतम कंटोर क्षेत्र थ्रेशोल्ड को सेट करता है। ScannerImageSplit.selectText.8=फोटो के लिए न्यूनतम कंटोर क्षेत्र थ्रेशोल्ड को सेट करता है।
ScannerImageSplit.selectText.9=बॉर्डर का आकार: ScannerImageSplit.selectText.9=बॉर्डर का आकार:
ScannerImageSplit.selectText.10=निकालने और जोड़ने के लिए जोड़ा जाने वाला बॉर्डर का आकार सेट करता है ताकि आउटपुट में सफेद बॉर्डर न आए (डिफ़ॉल्ट: 1)। ScannerImageSplit.selectText.10=निकालने और जोड़ने के लिए जोड़ा जाने वाला बॉर्डर का आकार सेट करता है ताकि आउटपुट में सफेद बॉर्डर न आए (डिफ़ॉल्ट: 1)।
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=रंगीन
pdfToImage.grey=ग्रे स्केल pdfToImage.grey=ग्रे स्केल
pdfToImage.blackwhite=काला और सफेद (डेटा खो सकता है!) pdfToImage.blackwhite=काला और सफेद (डेटा खो सकता है!)
pdfToImage.submit=परिवर्तित करें pdfToImage.submit=परिवर्तित करें
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimalna konturna površina:
ScannerImageSplit.selectText.8=Postavlja minimalni prag površine konture za fotografiju ScannerImageSplit.selectText.8=Postavlja minimalni prag površine konture za fotografiju
ScannerImageSplit.selectText.9=Veličina obruba: ScannerImageSplit.selectText.9=Veličina obruba:
ScannerImageSplit.selectText.10=Postavlja veličinu obruba koji se dodaje i uklanja kako bi se spriječili bijeli obrubi u ispisu (zadano: 1). ScannerImageSplit.selectText.10=Postavlja veličinu obruba koji se dodaje i uklanja kako bi se spriječili bijeli obrubi u ispisu (zadano: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Boja
pdfToImage.grey=Sivi tonovi pdfToImage.grey=Sivi tonovi
pdfToImage.blackwhite=Crno-bijelo (mogu se izgubiti podaci!) pdfToImage.blackwhite=Crno-bijelo (mogu se izgubiti podaci!)
pdfToImage.submit=Pretvori pdfToImage.submit=Pretvori
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimális kontúr terület:
ScannerImageSplit.selectText.8=A fotók minimális kontúrterületének beállítása ScannerImageSplit.selectText.8=A fotók minimális kontúrterületének beállítása
ScannerImageSplit.selectText.9=Keret mérete: ScannerImageSplit.selectText.9=Keret mérete:
ScannerImageSplit.selectText.10=A hozzáadott és eltávolított keret méretének beállítása a fehér keretek elkerülése érdekében a kimeneten (alapértelmezett: 1). ScannerImageSplit.selectText.10=A hozzáadott és eltávolított keret méretének beállítása a fehér keretek elkerülése érdekében a kimeneten (alapértelmezett: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=színes
pdfToImage.grey=szürkeárnyalatos pdfToImage.grey=szürkeárnyalatos
pdfToImage.blackwhite=fekete-fehér (adatvesztéssel járhat!) pdfToImage.blackwhite=fekete-fehér (adatvesztéssel járhat!)
pdfToImage.submit=Átalakítás pdfToImage.submit=Átalakítás
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Area Kontur Minimum:
ScannerImageSplit.selectText.8=Menetapkan ambang batas area kontur minimum untuk foto ScannerImageSplit.selectText.8=Menetapkan ambang batas area kontur minimum untuk foto
ScannerImageSplit.selectText.9=Ukuran Batas: ScannerImageSplit.selectText.9=Ukuran Batas:
ScannerImageSplit.selectText.10=Menetapkan ukuran batas yang ditambahkan dan dihapus untuk mencegah batas putih pada output (default: 1). ScannerImageSplit.selectText.10=Menetapkan ukuran batas yang ditambahkan dan dihapus untuk mencegah batas putih pada output (default: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Warna
pdfToImage.grey=Skala abu-abu pdfToImage.grey=Skala abu-abu
pdfToImage.blackwhite=Black and White (Bisa kehilangan data!) pdfToImage.blackwhite=Black and White (Bisa kehilangan data!)
pdfToImage.submit=Konversi pdfToImage.submit=Konversi
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -55,7 +55,7 @@ userNotFoundMessage=Utente non trovato.
incorrectPasswordMessage=La password attuale non è corretta. incorrectPasswordMessage=La password attuale non è corretta.
usernameExistsMessage=Il nuovo nome utente esiste già. usernameExistsMessage=Il nuovo nome utente esiste già.
invalidUsernameMessage=Nome utente non valido, il nome utente può contenere solo lettere, numeri e i seguenti caratteri speciali @._+- o deve essere un indirizzo email valido. invalidUsernameMessage=Nome utente non valido, il nome utente può contenere solo lettere, numeri e i seguenti caratteri speciali @._+- o deve essere un indirizzo email valido.
invalidPasswordMessage=The password must not be empty and must not have spaces at the beginning or end. invalidPasswordMessage=La password non deve essere vuota e non deve contenere spazi all'inizio o alla fine.
confirmPasswordErrorMessage=La nuova password e la conferma della nuova password devono corrispondere. confirmPasswordErrorMessage=La nuova password e la conferma della nuova password devono corrispondere.
deleteCurrentUserMessage=Impossibile eliminare l'utente attualmente connesso. deleteCurrentUserMessage=Impossibile eliminare l'utente attualmente connesso.
deleteUsernameExistsMessage=Il nome utente non esiste e non può essere eliminato. deleteUsernameExistsMessage=Il nome utente non esiste e non può essere eliminato.
@@ -179,7 +179,7 @@ adminUserSettings.user=Utente
adminUserSettings.addUser=Aggiungi un nuovo Utente adminUserSettings.addUser=Aggiungi un nuovo Utente
adminUserSettings.deleteUser=Elimina utente adminUserSettings.deleteUser=Elimina utente
adminUserSettings.confirmDeleteUser=L'utente deve essere eliminato? adminUserSettings.confirmDeleteUser=L'utente deve essere eliminato?
adminUserSettings.confirmChangeUserStatus=Should the user be disabled/enabled? adminUserSettings.confirmChangeUserStatus=L'utente dovrebbe essere disabilitato/abilitato?
adminUserSettings.usernameInfo=Il nome utente può contenere solo lettere, numeri e i seguenti caratteri speciali @._+- oppure deve essere un indirizzo email valido. adminUserSettings.usernameInfo=Il nome utente può contenere solo lettere, numeri e i seguenti caratteri speciali @._+- oppure deve essere un indirizzo email valido.
adminUserSettings.roles=Ruoli adminUserSettings.roles=Ruoli
adminUserSettings.role=Ruolo adminUserSettings.role=Ruolo
@@ -193,13 +193,13 @@ adminUserSettings.forceChange=Forza l'utente a cambiare nome username/password a
adminUserSettings.submit=Salva utente adminUserSettings.submit=Salva utente
adminUserSettings.changeUserRole=Cambia il ruolo dell'utente adminUserSettings.changeUserRole=Cambia il ruolo dell'utente
adminUserSettings.authenticated=Autenticato adminUserSettings.authenticated=Autenticato
adminUserSettings.editOwnProfil=Edit own profile adminUserSettings.editOwnProfil=Modifica il tuo profilo
adminUserSettings.enabledUser=enabled user adminUserSettings.enabledUser=utente abilitato
adminUserSettings.disabledUser=disabled user adminUserSettings.disabledUser=utente disabilitato
adminUserSettings.activeUsers=Active Users: adminUserSettings.activeUsers=Utenti attivi:
adminUserSettings.disabledUsers=Disabled Users: adminUserSettings.disabledUsers=Utenti disabili:
adminUserSettings.totalUsers=Total Users: adminUserSettings.totalUsers=Utenti totali:
adminUserSettings.lastRequest=Last Request adminUserSettings.lastRequest=Ultima richiesta
database.title=Importazione/Esportazione database database.title=Importazione/Esportazione database
@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Area di contorno minima:
ScannerImageSplit.selectText.8=Imposta l'area minima del contorno di una foto ScannerImageSplit.selectText.8=Imposta l'area minima del contorno di una foto
ScannerImageSplit.selectText.9=Spessore bordo: ScannerImageSplit.selectText.9=Spessore bordo:
ScannerImageSplit.selectText.10=Imposta lo spessore del bordo aggiunto o rimosso per prevenire bordi bianchi nel risultato (predefinito: 1). ScannerImageSplit.selectText.10=Imposta lo spessore del bordo aggiunto o rimosso per prevenire bordi bianchi nel risultato (predefinito: 1).
ScannerImageSplit.info=Python non è installato. È necessario per l'esecuzione.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=A colori
pdfToImage.grey=Scala di grigi pdfToImage.grey=Scala di grigi
pdfToImage.blackwhite=Bianco e Nero (potresti perdere dettagli!) pdfToImage.blackwhite=Bianco e Nero (potresti perdere dettagli!)
pdfToImage.submit=Converti pdfToImage.submit=Converti
pdfToImage.info=Python non è installato.È richiesto per la conversione WebP.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=最小輪郭面積:
ScannerImageSplit.selectText.8=画像の最小の輪郭面積のしきい値を設定。 ScannerImageSplit.selectText.8=画像の最小の輪郭面積のしきい値を設定。
ScannerImageSplit.selectText.9=境界線サイズ: ScannerImageSplit.selectText.9=境界線サイズ:
ScannerImageSplit.selectText.10=出力に白い縁取りが出ないように追加・削除される境界線の大きさを設定 (初期値:1)。 ScannerImageSplit.selectText.10=出力に白い縁取りが出ないように追加・削除される境界線の大きさを設定 (初期値:1)。
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=カラー
pdfToImage.grey=グレースケール pdfToImage.grey=グレースケール
pdfToImage.blackwhite=白黒 (データが失われる可能性があります!) pdfToImage.blackwhite=白黒 (データが失われる可能性があります!)
pdfToImage.submit=変換 pdfToImage.submit=変換
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=최소 윤곽 영역:
ScannerImageSplit.selectText.8=사진의 최소 윤곽선 영역 임계값을 설정합니다. ScannerImageSplit.selectText.8=사진의 최소 윤곽선 영역 임계값을 설정합니다.
ScannerImageSplit.selectText.9=테두리 크기: ScannerImageSplit.selectText.9=테두리 크기:
ScannerImageSplit.selectText.10=출력에서 흰색 테두리를 방지하기 위해 추가 및 제거되는 테두리의 크기를 설정합니다(기본값: 1). ScannerImageSplit.selectText.10=출력에서 흰색 테두리를 방지하기 위해 추가 및 제거되는 테두리의 크기를 설정합니다(기본값: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=컬러
pdfToImage.grey=그레이스케일 pdfToImage.grey=그레이스케일
pdfToImage.blackwhite=흑백 (데이터 손실 가능성 있음!) pdfToImage.blackwhite=흑백 (데이터 손실 가능성 있음!)
pdfToImage.submit=변환 pdfToImage.submit=변환
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimum contour oppervlakte:
ScannerImageSplit.selectText.8=Stelt de minimale contour oppervlakte drempel in voor een foto ScannerImageSplit.selectText.8=Stelt de minimale contour oppervlakte drempel in voor een foto
ScannerImageSplit.selectText.9=Randgrootte: ScannerImageSplit.selectText.9=Randgrootte:
ScannerImageSplit.selectText.10=Stelt de grootte van de toegevoegde en verwijderde rand in om witte randen in de uitvoer te voorkomen (standaard: 1). ScannerImageSplit.selectText.10=Stelt de grootte van de toegevoegde en verwijderde rand in om witte randen in de uitvoer te voorkomen (standaard: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Kleur
pdfToImage.grey=Grijstinten pdfToImage.grey=Grijstinten
pdfToImage.blackwhite=Zwart en wit (kan data verliezen!) pdfToImage.blackwhite=Zwart en wit (kan data verliezen!)
pdfToImage.submit=Omzetten pdfToImage.submit=Omzetten
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimumskonturområde:
ScannerImageSplit.selectText.8=Angir minimumskonturområde terskel for et bilde ScannerImageSplit.selectText.8=Angir minimumskonturområde terskel for et bilde
ScannerImageSplit.selectText.9=Kantstørrelse: ScannerImageSplit.selectText.9=Kantstørrelse:
ScannerImageSplit.selectText.10=Angir størrelsen på kanten som legges til og fjernes for å forhindre hvite kanter i utdataen (standard: 1). ScannerImageSplit.selectText.10=Angir størrelsen på kanten som legges til og fjernes for å forhindre hvite kanter i utdataen (standard: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Farge
pdfToImage.grey=Gråtone pdfToImage.grey=Gråtone
pdfToImage.blackwhite=Svart-hvitt (kan miste data!) pdfToImage.blackwhite=Svart-hvitt (kan miste data!)
pdfToImage.submit=Konverter pdfToImage.submit=Konverter
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimalny obszar konturu:
ScannerImageSplit.selectText.8=Ustawia próg minimalnego obszaru konturu dla zdjęcia ScannerImageSplit.selectText.8=Ustawia próg minimalnego obszaru konturu dla zdjęcia
ScannerImageSplit.selectText.9=Rozmiar obramowania: ScannerImageSplit.selectText.9=Rozmiar obramowania:
ScannerImageSplit.selectText.10=Ustawia rozmiar dodawanego i usuwanego obramowania, aby uniknąć białych obramowań na wyjściu (domyślnie: 1). ScannerImageSplit.selectText.10=Ustawia rozmiar dodawanego i usuwanego obramowania, aby uniknąć białych obramowań na wyjściu (domyślnie: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Kolor
pdfToImage.grey=Odcień szarości pdfToImage.grey=Odcień szarości
pdfToImage.blackwhite=Czarno-biały (może spowodować utratę danych!) pdfToImage.blackwhite=Czarno-biały (może spowodować utratę danych!)
pdfToImage.submit=Konwertuj pdfToImage.submit=Konwertuj
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Área mínima de contorno:
ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto
ScannerImageSplit.selectText.9=Tamanho da borda: ScannerImageSplit.selectText.9=Tamanho da borda:
ScannerImageSplit.selectText.10=Define o tamanho da borda adicionada e removida para evitar bordas brancas na saída (padrão: 1). ScannerImageSplit.selectText.10=Define o tamanho da borda adicionada e removida para evitar bordas brancas na saída (padrão: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Colorida
pdfToImage.grey=Escala de Cinza pdfToImage.grey=Escala de Cinza
pdfToImage.blackwhite=Preto e Branco (pode perder de dados!) pdfToImage.blackwhite=Preto e Branco (pode perder de dados!)
pdfToImage.submit=Converter pdfToImage.submit=Converter
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Área mínima de contorno:
ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto ScannerImageSplit.selectText.8=Define o limite mínimo da área de contorno para uma foto
ScannerImageSplit.selectText.9=Tamanho do contorno: ScannerImageSplit.selectText.9=Tamanho do contorno:
ScannerImageSplit.selectText.10=Define o tamanho do contorno adicionado e removido para evitar contornos brancos na saída (padrão: 1). ScannerImageSplit.selectText.10=Define o tamanho do contorno adicionado e removido para evitar contornos brancos na saída (padrão: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Colorida
pdfToImage.grey=Escala de Cinza pdfToImage.grey=Escala de Cinza
pdfToImage.blackwhite=Preto e Branco (pode resultar em perda de dados!) pdfToImage.blackwhite=Preto e Branco (pode resultar em perda de dados!)
pdfToImage.submit=Converter pdfToImage.submit=Converter
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Arie minimă a conturului:
ScannerImageSplit.selectText.8=Stabilește pragul minim de arie a conturului pentru o fotografie. ScannerImageSplit.selectText.8=Stabilește pragul minim de arie a conturului pentru o fotografie.
ScannerImageSplit.selectText.9=Mărimea marginii: ScannerImageSplit.selectText.9=Mărimea marginii:
ScannerImageSplit.selectText.10=Stabilește mărimea marginii adăugate și eliminate pentru a evita marginile albe în rezultat (implicit: 1). ScannerImageSplit.selectText.10=Stabilește mărimea marginii adăugate și eliminate pentru a evita marginile albe în rezultat (implicit: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Culoare
pdfToImage.grey=Scală de gri pdfToImage.grey=Scală de gri
pdfToImage.blackwhite=Alb și negru (Poate pierde date!) pdfToImage.blackwhite=Alb și negru (Poate pierde date!)
pdfToImage.submit=Convertă pdfToImage.submit=Convertă
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Минимальная площадь конту
ScannerImageSplit.selectText.8=Устанавливает минимальный порог области контура для фотографии ScannerImageSplit.selectText.8=Устанавливает минимальный порог области контура для фотографии
ScannerImageSplit.selectText.9=Размер границы: ScannerImageSplit.selectText.9=Размер границы:
ScannerImageSplit.selectText.10=Устанавливает размер добавляемой и удаляемой границы, чтобы предотвратить появление белых границ на выходе (по умолчанию: 1). ScannerImageSplit.selectText.10=Устанавливает размер добавляемой и удаляемой границы, чтобы предотвратить появление белых границ на выходе (по умолчанию: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Цвет
pdfToImage.grey=Оттенки серого pdfToImage.grey=Оттенки серого
pdfToImage.blackwhite=Черно-белый (может потерять данные!) pdfToImage.blackwhite=Черно-белый (может потерять данные!)
pdfToImage.submit=Конвертировать pdfToImage.submit=Конвертировать
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimálna plocha obrysu:
ScannerImageSplit.selectText.8=Nastaví minimálnu prahovú hodnotu plochy obrysu pre fotografiu ScannerImageSplit.selectText.8=Nastaví minimálnu prahovú hodnotu plochy obrysu pre fotografiu
ScannerImageSplit.selectText.9=Veľkosť okraja: ScannerImageSplit.selectText.9=Veľkosť okraja:
ScannerImageSplit.selectText.10=Nastaví veľkosť okraja pridaného a odstráneného, aby sa zabránilo bielym okrajom vo výstupe (predvolené: 1). ScannerImageSplit.selectText.10=Nastaví veľkosť okraja pridaného a odstráneného, aby sa zabránilo bielym okrajom vo výstupe (predvolené: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Farba
pdfToImage.grey=Odtiene šedej pdfToImage.grey=Odtiene šedej
pdfToImage.blackwhite=Čierno-biele (Môže stratiť údaje!) pdfToImage.blackwhite=Čierno-biele (Môže stratiť údaje!)
pdfToImage.submit=Konvertovať pdfToImage.submit=Konvertovať
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimalna površina konture:
ScannerImageSplit.selectText.8=Postavlja minimalni prag površine konture za fotografiju ScannerImageSplit.selectText.8=Postavlja minimalni prag površine konture za fotografiju
ScannerImageSplit.selectText.9=Veličina ivice: ScannerImageSplit.selectText.9=Veličina ivice:
ScannerImageSplit.selectText.10=Postavlja veličinu ivice dodate i uklonjene kako bi se sprečile bele ivice u izlazu (podrazumevano: 1). ScannerImageSplit.selectText.10=Postavlja veličinu ivice dodate i uklonjene kako bi se sprečile bele ivice u izlazu (podrazumevano: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Boja
pdfToImage.grey=Nijanse sive pdfToImage.grey=Nijanse sive
pdfToImage.blackwhite=Crno-belo (Može izgubiti podatke!) pdfToImage.blackwhite=Crno-belo (Može izgubiti podatke!)
pdfToImage.submit=Konvertuj pdfToImage.submit=Konvertuj
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minsta konturarea:
ScannerImageSplit.selectText.8=Ställer in minsta tröskelvärde för konturarea för ett foto ScannerImageSplit.selectText.8=Ställer in minsta tröskelvärde för konturarea för ett foto
ScannerImageSplit.selectText.9=Kantstorlek: ScannerImageSplit.selectText.9=Kantstorlek:
ScannerImageSplit.selectText.10=Ställer in storleken på kanten som läggs till och tas bort för att förhindra vita kanter i utdata (standard: 1). ScannerImageSplit.selectText.10=Ställer in storleken på kanten som läggs till och tas bort för att förhindra vita kanter i utdata (standard: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Färg
pdfToImage.grey=Gråskala pdfToImage.grey=Gråskala
pdfToImage.blackwhite=Svartvitt (kan förlora data!) pdfToImage.blackwhite=Svartvitt (kan förlora data!)
pdfToImage.submit=Konvertera pdfToImage.submit=Konvertera
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=พื้นที่เค้าโครงข
ScannerImageSplit.selectText.8=ตั้งค่าเกณฑ์พื้นที่เค้าโครงขั้นต่ำสำหรับรูปภาพ ScannerImageSplit.selectText.8=ตั้งค่าเกณฑ์พื้นที่เค้าโครงขั้นต่ำสำหรับรูปภาพ
ScannerImageSplit.selectText.9=ขนาดขอบ: ScannerImageSplit.selectText.9=ขนาดขอบ:
ScannerImageSplit.selectText.10=ตั้งค่าขนาดขอบที่เพิ่มและลบเพื่อป้องกันขอบขาวในผลลัพธ์ (ค่าเริ่มต้น: 1) ScannerImageSplit.selectText.10=ตั้งค่าขนาดขอบที่เพิ่มและลบเพื่อป้องกันขอบขาวในผลลัพธ์ (ค่าเริ่มต้น: 1)
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=สี
pdfToImage.grey=ระดับสีเทา pdfToImage.grey=ระดับสีเทา
pdfToImage.blackwhite=ขาวดำ (อาจสูญเสียข้อมูล!) pdfToImage.blackwhite=ขาวดำ (อาจสูญเสียข้อมูล!)
pdfToImage.submit=แปลง pdfToImage.submit=แปลง
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Minimum Kontur Alanı:
ScannerImageSplit.selectText.8=Bir fotoğraf için minimum kontur alanı eşiğini ayarlar ScannerImageSplit.selectText.8=Bir fotoğraf için minimum kontur alanı eşiğini ayarlar
ScannerImageSplit.selectText.9=Kenar Boyutu: ScannerImageSplit.selectText.9=Kenar Boyutu:
ScannerImageSplit.selectText.10=Çıktıda beyaz kenarların önlenmesi için eklenen ve kaldırılan kenarın boyutunu ayarlar (varsayılan: 1). ScannerImageSplit.selectText.10=Çıktıda beyaz kenarların önlenmesi için eklenen ve kaldırılan kenarın boyutunu ayarlar (varsayılan: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Renk
pdfToImage.grey=Gri tonlama pdfToImage.grey=Gri tonlama
pdfToImage.blackwhite=Siyah ve Beyaz (Veri kaybolabilir!) pdfToImage.blackwhite=Siyah ve Beyaz (Veri kaybolabilir!)
pdfToImage.submit=Dönüştür pdfToImage.submit=Dönüştür
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Мінімальна площа контуру:
ScannerImageSplit.selectText.8=Встановлює мінімальний поріг площі контуру для фотографії ScannerImageSplit.selectText.8=Встановлює мінімальний поріг площі контуру для фотографії
ScannerImageSplit.selectText.9=Розмір рамки: ScannerImageSplit.selectText.9=Розмір рамки:
ScannerImageSplit.selectText.10=Встановлює розмір додаваної та видаляної рамки, щоб запобігти появі білих рамок на виході (за замовчуванням: 1). ScannerImageSplit.selectText.10=Встановлює розмір додаваної та видаляної рамки, щоб запобігти появі білих рамок на виході (за замовчуванням: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Колір
pdfToImage.grey=Відтінки сірого pdfToImage.grey=Відтінки сірого
pdfToImage.blackwhite=Чорно-білий (може втратити дані!) pdfToImage.blackwhite=Чорно-білий (може втратити дані!)
pdfToImage.submit=Конвертувати pdfToImage.submit=Конвертувати
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=Diện tích đường viền tối thiểu:
ScannerImageSplit.selectText.8=Đặt ngưỡng diện tích đường viền tối thiểu cho một ảnh ScannerImageSplit.selectText.8=Đặt ngưỡng diện tích đường viền tối thiểu cho một ảnh
ScannerImageSplit.selectText.9=Kích thước viền: ScannerImageSplit.selectText.9=Kích thước viền:
ScannerImageSplit.selectText.10=Đặt kích thước của viền được thêm vào và loại bỏ để ngăn chặn viền trắng trong đầu ra (mặc định: 1). ScannerImageSplit.selectText.10=Đặt kích thước của viền được thêm vào và loại bỏ để ngăn chặn viền trắng trong đầu ra (mặc định: 1).
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=Màu
pdfToImage.grey=Thang độ xám pdfToImage.grey=Thang độ xám
pdfToImage.blackwhite=Đen trắng (Có thể mất dữ liệu!) pdfToImage.blackwhite=Đen trắng (Có thể mất dữ liệu!)
pdfToImage.submit=Chuyển đổi pdfToImage.submit=Chuyển đổi
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=最小轮廓面积:
ScannerImageSplit.selectText.8=设置照片的最小轮廓面积阈值。 ScannerImageSplit.selectText.8=设置照片的最小轮廓面积阈值。
ScannerImageSplit.selectText.9=边框尺寸: ScannerImageSplit.selectText.9=边框尺寸:
ScannerImageSplit.selectText.10=设置添加和删除的边框大小以防止输出中出现白边默认值1 ScannerImageSplit.selectText.10=设置添加和删除的边框大小以防止输出中出现白边默认值1
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=颜色
pdfToImage.grey=灰度 pdfToImage.grey=灰度
pdfToImage.blackwhite=黑白(可能会丢失数据!)。 pdfToImage.blackwhite=黑白(可能会丢失数据!)。
pdfToImage.submit=转换 pdfToImage.submit=转换
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -775,6 +775,7 @@ ScannerImageSplit.selectText.7=最小輪廓區域:
ScannerImageSplit.selectText.8=設定照片的最小輪廓區域閾值 ScannerImageSplit.selectText.8=設定照片的最小輪廓區域閾值
ScannerImageSplit.selectText.9=邊框大小: ScannerImageSplit.selectText.9=邊框大小:
ScannerImageSplit.selectText.10=設定新增和移除的邊框大小以防止輸出中的白色邊框預設1 ScannerImageSplit.selectText.10=設定新增和移除的邊框大小以防止輸出中的白色邊框預設1
ScannerImageSplit.info=Python is not installed. It is required to run.
#OCR #OCR
@@ -925,6 +926,7 @@ pdfToImage.color=顏色
pdfToImage.grey=灰度 pdfToImage.grey=灰度
pdfToImage.blackwhite=黑白(可能會遺失資料!) pdfToImage.blackwhite=黑白(可能會遺失資料!)
pdfToImage.submit=轉換 pdfToImage.submit=轉換
pdfToImage.info=Python is not installed. Required for WebP conversion.
#addPassword #addPassword

View File

@@ -37,7 +37,7 @@ $(document).ready(function () {
try { try {
if (remoteCall === true) { if (remoteCall === true) {
if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) { if (override === "multi" || (!multipleInputsForSingleRequest && files.length > 1 && override !== "single")) {
await submitMultiPdfForm(url, files); await submitMultiPdfForm(url, files);
} else { } else {
await handleSingleDownload(url, formData); await handleSingleDownload(url, formData);

View File

@@ -24,7 +24,7 @@
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-split-pdf'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-split-pdf'}">
<p th:text="#{autoSplitPDF.formPrompt}"></p> <p th:text="#{autoSplitPDF.formPrompt}"></p>
<div <div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"> th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
</div> </div>
<div class="form-check ms-3"> <div class="form-check ms-3">
<input type="checkbox" name="duplexMode" id="duplexMode"> <input type="checkbox" name="duplexMode" id="duplexMode">

View File

@@ -15,7 +15,7 @@
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{BookToPDF.header}"></h2> <h2 th:text="#{BookToPDF.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/book/pdf'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/book/pdf'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false)}"></div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{BookToPDF.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{BookToPDF.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{BookToPDF.credit}"></p> <p class="mt-3" th:text="#{BookToPDF.credit}"></p>

View File

@@ -21,7 +21,7 @@
</div> </div>
<p th:text="#{processTimeWarning}"></p> <p th:text="#{processTimeWarning}"></p>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/file/pdf'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/file/pdf'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false)}"></div>
<a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button" <a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button"
aria-expanded="false" aria-controls="info" th:text="#{fileToPDF.supportedFileTypesInfo}"></a> aria-expanded="false" aria-controls="info" th:text="#{fileToPDF.supportedFileTypesInfo}"></a>
<div class="collapse" id="info"> <div class="collapse" id="info">

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{HTMLToPDF.header}"></span> <span class="tool-header-text" th:text="#{HTMLToPDF.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/html/pdf'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/html/pdf'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/html,application/zip' )}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='text/html,application/zip' )}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label> <label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label>
<input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1"> <input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1">

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{imageToPDF.header}"></span> <span class="tool-header-text" th:text="#{imageToPDF.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/img/pdf'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/img/pdf'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='image/*', inputText=#{imgPrompt})}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label> <label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label>
<select class="form-control" id="fitOption" name="fitOption"> <select class="form-control" id="fitOption" name="fitOption">

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{MarkdownToPDF.header}"></span> <span class="tool-header-text" th:text="#{MarkdownToPDF.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/markdown/pdf'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/markdown/pdf'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/markdown')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='text/markdown')}"></div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{MarkdownToPDF.help}"></p> <p class="mt-3" th:text="#{MarkdownToPDF.help}"></p>

View File

@@ -15,7 +15,7 @@
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{PDFToBook.header}"></h2> <h2 th:text="#{PDFToBook.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/book'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/book'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{PDFToBook.selectText.1}"></label> <label th:text="#{PDFToBook.selectText.1}"></label>
<select class="form-control" name="outputFormat"> <select class="form-control" name="outputFormat">

View File

@@ -18,7 +18,7 @@
</div> </div>
<form id="PDFToCSVForm" th:action="@{'/api/v1/convert/pdf/csv'}" method="post" enctype="multipart/form-data"> <form id="PDFToCSVForm" th:action="@{'/api/v1/convert/pdf/csv'}" method="post" enctype="multipart/form-data">
<input id="pageId" type="hidden" name="pageId"> <input id="pageId" type="hidden" name="pageId">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<button type="submit" class="btn btn-primary" th:text="#{PDFToCSV.submit}"></button> <button type="submit" class="btn btn-primary" th:text="#{PDFToCSV.submit}"></button>
</form> </form>
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p> <p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{PDFToHTML.header}"></span> <span class="tool-header-text" th:text="#{PDFToHTML.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/html'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/html'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToHTML.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToHTML.submit}"></button>
</form> </form>

View File

@@ -18,8 +18,9 @@
<span class="tool-header-text" th:text="#{pdfToImage.header}"></span> <span class="tool-header-text" th:text="#{pdfToImage.header}"></span>
</div> </div>
<p th:text="#{processTimeWarning}"></p> <p th:text="#{processTimeWarning}"></p>
<p th:if="${!isPython}" th:text="#{pdfToImage.info}">Python is not installed. Required for WebP conversion.</p>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/img'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/img'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{pdfToImage.selectText}"></label> <label th:text="#{pdfToImage.selectText}"></label>
<select class="form-control" name="imageFormat"> <select class="form-control" name="imageFormat">
@@ -28,7 +29,7 @@
<option value="gif">GIF</option> <option value="gif">GIF</option>
<option value="tiff">TIFF</option> <option value="tiff">TIFF</option>
<option value="bmp">BMP</option> <option value="bmp">BMP</option>
<option value="webp">WEPB</option> <option th:if="${isPython}" value="webp">WEPB</option>
</select> </select>
</div> </div>
<div class="mb-3"> <div class="mb-3">

View File

@@ -19,7 +19,7 @@
</div> </div>
<p th:text="#{pdfToPDFA.tip}"></p> <p th:text="#{pdfToPDFA.tip}"></p>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/pdfa'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/pdfa'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="outputFormat" th:text="#{pdfToPDFA.outputFormat}"></label> <label for="outputFormat" th:text="#{pdfToPDFA.outputFormat}"></label>
<select class="form-control" name="outputFormat" id="outputFormat"> <select class="form-control" name="outputFormat" id="outputFormat">

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{PDFToPresentation.header}"></span> <span class="tool-header-text" th:text="#{PDFToPresentation.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/presentation'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/presentation'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{PDFToPresentation.selectText.1}"></label> <label th:text="#{PDFToPresentation.selectText.1}"></label>
<select class="form-control" name="outputFormat"> <select class="form-control" name="outputFormat">

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{PDFToText.header}"></span> <span class="tool-header-text" th:text="#{PDFToText.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/text'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/text'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{PDFToText.selectText.1}"></label> <label th:text="#{PDFToText.selectText.1}"></label>
<select class="form-control" name="outputFormat"> <select class="form-control" name="outputFormat">

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{PDFToWord.header}"></span> <span class="tool-header-text" th:text="#{PDFToWord.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/word'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/word'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{PDFToWord.selectText.1}"></label> <label th:text="#{PDFToWord.selectText.1}"></label>
<select class="form-control" name="outputFormat"> <select class="form-control" name="outputFormat">

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{PDFToXML.header}"></span> <span class="tool-header-text" th:text="#{PDFToXML.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/xml'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/xml'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToXML.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToXML.submit}"></button>
</form> </form>

View File

@@ -17,7 +17,7 @@
<span class="tool-header-text" th:text="#{crop.header}"></span> <span class="tool-header-text" th:text="#{crop.header}"></span>
</div> </div>
<form id="cropForm" th:action="@{'/api/v1/general/crop'}" method="post" enctype="multipart/form-data"> <form id="cropForm" th:action="@{'/api/v1/general/crop'}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<input id="x" type="hidden" name="x"> <input id="x" type="hidden" name="x">
<input id="y" type="hidden" name="y"> <input id="y" type="hidden" name="y">
<input id="width" type="hidden" name="width"> <input id="width" type="hidden" name="width">

View File

@@ -17,7 +17,7 @@
<span class="tool-header-text" th:text="#{pageExtracter.header}"></span> <span class="tool-header-text" th:text="#{pageExtracter.header}"></span>
</div> </div>
<form th:action="@{'/api/v1/general/rearrange-pages'}" method="post" enctype="multipart/form-data"> <form th:action="@{'/api/v1/general/rearrange-pages'}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<input type="hidden" id="customMode" name="customMode" value=""> <input type="hidden" id="customMode" name="customMode" value="">
<div class="mb-3"> <div class="mb-3">
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label> <label for="pageOrder" th:text="#{pageOrderPrompt}"></label>

View File

@@ -144,17 +144,18 @@
</dialog> </dialog>
</th:block> </th:block>
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false"> <th:block th:fragment="fileSelector(name, multipleInputsForSingleRequest)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, disableMultipleFiles=${disableMultipleFiles} ?: false, notRequired=${notRequired} ?: false">
<script th:inline="javascript"> <script th:inline="javascript">
const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ ''; const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
const multiple = /*[[${multiple}]]*/ false; const multipleInputsForSingleRequest = /*[[${multipleInputsForSingleRequest}]]*/ false;
const disableMultipleFiles = /*[[${disableMultipleFiles}]]*/ false;
const remoteCall = /*[[${remoteCall}]]*/ true; const remoteCall = /*[[${remoteCall}]]*/ true;
</script> </script>
<script th:src="@{'/js/downloader.js'}"></script> <script th:src="@{'/js/downloader.js'}"></script>
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}"> <div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
<div class="mb-3"> <div class="mb-3">
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" th:attr="multiple=${multiple}" th:required="${notRequired} ? null : 'required'"> <input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" th:attr="multiple=${!disableMultipleFiles}" th:required="${notRequired} ? null : 'required'">
</div> </div>
<div class="selected-files"></div> <div class="selected-files"></div>
</div> </div>

View File

@@ -20,7 +20,7 @@
<form action="api/v1/general/merge-pdfs" method="post" enctype="multipart/form-data"> <form action="api/v1/general/merge-pdfs" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<label th:text="#{multiPdfDropPrompt}" for="fileInput-input"></label> <label th:text="#{multiPdfDropPrompt}" for="fileInput-input"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=true, accept='application/pdf')}"></div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<input type="checkbox" name="removeCertSign" id="removeCertSign"> <input type="checkbox" name="removeCertSign" id="removeCertSign">

View File

@@ -20,7 +20,7 @@
</div> </div>
<!-- pdf selector --> <!-- pdf selector -->
<div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<script> <script>
let originalFileName = ''; let originalFileName = '';
document.querySelector('input[name=pdf-upload]').addEventListener('change', async (event) => { document.querySelector('input[name=pdf-upload]').addEventListener('change', async (event) => {
@@ -46,7 +46,7 @@
<div class="tab-group show-on-file-selected"> <div class="tab-group show-on-file-selected">
<div class="tab-container" th:title="#{addImage.upload}"> <div class="tab-container" th:title="#{addImage.upload}">
<div th:replace="~{fragments/common :: fileSelector(name='image-upload', multiple=true, accept='image/*', inputText=#{imgPrompt})}"></div> <div th:replace="~{fragments/common :: fileSelector(name='image-upload', multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}"></div>
<script> <script>
const imageUpload = document.querySelector('input[name=image-upload]'); const imageUpload = document.querySelector('input[name=image-upload]');
imageUpload.addEventListener('change', e => { imageUpload.addEventListener('change', e => {

View File

@@ -61,7 +61,7 @@
<span class="tool-header-text" th:text="#{addPageNumbers.header}"></span> <span class="tool-header-text" th:text="#{addPageNumbers.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/add-page-numbers'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/add-page-numbers'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<br> <br>
<div class="mb-3"> <div class="mb-3">
<label for="customMargin" th:text="#{addPageNumbers.selectText.2}"></label> <label for="customMargin" th:text="#{addPageNumbers.selectText.2}"></label>

View File

@@ -40,7 +40,7 @@
<span class="tool-header-text" th:text="#{adjustContrast.header}"></span> <span class="tool-header-text" th:text="#{adjustContrast.header}"></span>
</div> </div>
<div class="col-md-8"> <div class="col-md-8">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
</div> </div>
<br> <br>
<canvas id="contrast-pdf-canvas"></canvas> <canvas id="contrast-pdf-canvas"></canvas>

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{autoCrop.header}"></span> <span class="tool-header-text" th:text="#{autoCrop.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-crop'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-crop'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{autoCrop.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{autoCrop.submit}"></button>
</form> </form>

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{auto-rename.header}"></span> <span class="tool-header-text" th:text="#{auto-rename.header}"></span>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-rename'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-rename'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{auto-rename.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{auto-rename.submit}"></button>
</form> </form>

View File

@@ -17,7 +17,7 @@
<span class="tool-header-text" th:text="#{changeMetadata.header}"></span> <span class="tool-header-text" th:text="#{changeMetadata.header}"></span>
</div> </div>
<form method="post" id="form1" enctype="multipart/form-data" th:action="@{'/api/v1/misc/update-metadata'}"> <form method="post" id="form1" enctype="multipart/form-data" th:action="@{'/api/v1/misc/update-metadata'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p> <p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p>
<div class="form-check mb-3-inline ms-3"> <div class="form-check mb-3-inline ms-3">
<input type="checkbox" id="deleteAll" name="deleteAll"> <input type="checkbox" id="deleteAll" name="deleteAll">

View File

@@ -51,8 +51,8 @@
<span class="material-symbols-rounded tool-header-icon other">compare</span> <span class="material-symbols-rounded tool-header-icon other">compare</span>
<span class="tool-header-text" th:text="#{compare.header}"></span> <span class="tool-header-text" th:text="#{compare.header}"></span>
</div> </div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
<div class="row"> <div class="row">
<div class="flex-container"> <div class="flex-container">

View File

@@ -21,7 +21,7 @@
</div> </div>
<form action="#" th:action="@{'/api/v1/misc/compress-pdf'}" method="post" enctype="multipart/form-data"> <form action="#" th:action="@{'/api/v1/misc/compress-pdf'}" method="post" enctype="multipart/form-data">
<div <div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"> th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
</div> </div>
<div class="card mb-3"> <div class="card mb-3">
<div class="card-body"> <div class="card-body">

View File

@@ -18,8 +18,10 @@
<span class="tool-header-text" th:text="#{home.ScannerImageSplit.title}"></span> <span class="tool-header-text" th:text="#{home.ScannerImageSplit.title}"></span>
</div> </div>
<form id="multiPdfForm" th:action="@{'/api/v1/misc/extract-image-scans'}" method="post" enctype="multipart/form-data"> <p th:if="${!isPython}" th:text="#{ScannerImageSplit.info}" class="alert alert-success text-center">Python is not installed. It is required to run.</p>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*, application/pdf')}"></div>
<form th:if="${isPython}" id="multiPdfForm" th:action="@{'/api/v1/misc/extract-image-scans'}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='image/*, application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="angleThreshold" th:text="#{ScannerImageSplit.selectText.1}"></label> <label for="angleThreshold" th:text="#{ScannerImageSplit.selectText.1}"></label>
<input type="number" class="form-control" id="angleThreshold" name="angle_threshold" value="10"> <input type="number" class="form-control" id="angleThreshold" name="angle_threshold" value="10">

View File

@@ -18,7 +18,7 @@
<span class="tool-header-text" th:text="#{extractImages.header}"></span> <span class="tool-header-text" th:text="#{extractImages.header}"></span>
</div> </div>
<form id="multiPdfForm" th:action="@{'/api/v1/misc/extract-images'}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{'/api/v1/misc/extract-images'}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{extractImages.selectText}"></label> <label th:text="#{extractImages.selectText}"></label>
<select class="form-control" name="format"> <select class="form-control" name="format">

View File

@@ -15,7 +15,7 @@
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{fakeScan.header}"></h2> <h2 th:text="#{fakeScan.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/fake-scan'}"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/fake-scan'}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fakeScan.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fakeScan.submit}"></button>
</form> </form>

View File

@@ -19,7 +19,7 @@
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/flatten'}" id="pdfForm" class="mb-3"> <form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/flatten'}" id="pdfForm" class="mb-3">
<div class="custom-file"> <div class="custom-file">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
</div> </div>
<div class="form-check ms-3"> <div class="form-check ms-3">
<input type="checkbox" id="flattenOnlyForms" name="flattenOnlyForms"> <input type="checkbox" id="flattenOnlyForms" name="flattenOnlyForms">

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