Compare commits
14 Commits
fa564c47ce
...
99b70e6265
Author | SHA1 | Date |
---|---|---|
dependabot[bot] | 99b70e6265 | |
github-actions[bot] | 4fea8d10f8 | |
Anthony Stirling | 8c9d6f7b66 | |
Anthony Stirling | 30444fc9bb | |
Han | 70349d642b | |
albanobattistella | afaec64afd | |
github-actions[bot] | 2a9fdff605 | |
Anthony Stirling | 34c7ee46a0 | |
phfuh | 5ee702f364 | |
Ludy | 1b5d21a22e | |
Anthony Stirling | c3e5157dee | |
Anthony Stirling | 6d859e4c25 | |
diemade | 95a9aca5b5 | |
github-actions[bot] | 4c8f582c56 |
|
@ -27,6 +27,10 @@ Please make sure your Pull Request adheres to the following guidelines:
|
|||
|
||||
If you would like to add or modify a translation, please see [How to add new languages to Stirling-PDF](HowToAddNewLanguage.md). Also, please create a Pull Request so others can use it!
|
||||
|
||||
## Docs
|
||||
|
||||
Documentation for Stirling-PDF is handled in a seperate repository. Please see [Docs repository](https://github.com/Stirling-Tools/Stirling-Tools.github.io) or use "edit this page"-button at the bottom of each page at [https://stirlingtools.com/docs/](https://stirlingtools.com/docs/).
|
||||
|
||||
## Fixing Bugs or Adding a New Feature
|
||||
|
||||
First, make sure you've read the section [Pull Requests](#pull-requests).
|
||||
|
|
|
@ -182,12 +182,12 @@ Stirling PDF currently supports 27!
|
|||
| Basque (Euskara) (eu_ES) | ![75%](https://geps.dev/progress/75) |
|
||||
| Japanese (日本語) (ja_JP) | ![93%](https://geps.dev/progress/93) |
|
||||
| Dutch (Nederlands) (nl_NL) | ![91%](https://geps.dev/progress/91) |
|
||||
| Greek (Ελληνικά) (el_GR) | ![92%](https://geps.dev/progress/92) |
|
||||
| Greek (Ελληνικά) (el_GR) | ![91%](https://geps.dev/progress/91) |
|
||||
| Turkish (Türkçe) (tr_TR) | ![99%](https://geps.dev/progress/99) |
|
||||
| Indonesia (Bahasa Indonesia) (id_ID) | ![87%](https://geps.dev/progress/87) |
|
||||
| Indonesia (Bahasa Indonesia) (id_ID) | ![86%](https://geps.dev/progress/86) |
|
||||
| Hindi (हिंदी) (hi_IN) | ![87%](https://geps.dev/progress/87) |
|
||||
| Hungarian (Magyar) (hu_HU) | ![86%](https://geps.dev/progress/86) |
|
||||
| Bulgarian (Български) (bg_BG) | ![82%](https://geps.dev/progress/82) |
|
||||
| Bulgarian (Български) (bg_BG) | ![81%](https://geps.dev/progress/81) |
|
||||
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![88%](https://geps.dev/progress/88) |
|
||||
| Ukrainian (Українська) (uk_UA) | ![93%](https://geps.dev/progress/93) |
|
||||
|
||||
|
@ -201,7 +201,7 @@ Stirling PDF allows easy customization of the app.
|
|||
Includes things like
|
||||
|
||||
- Custom application name
|
||||
- Custom slogans, icons, images, and even custom HTML (via file overrides)
|
||||
- Custom slogans, icons, HTML, images CSS etc (via file overrides)
|
||||
|
||||
There are two options for this, either using the generated settings file ``settings.yml``
|
||||
This file is located in the ``/configs`` directory and follows standard YAML formatting
|
||||
|
@ -229,6 +229,7 @@ system:
|
|||
customStaticFilePath: '/customFiles/static/' # Directory path for custom static files
|
||||
showUpdate: true # see when a new update is available
|
||||
showUpdateOnlyAdmin: false # Only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
|
||||
customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template html files
|
||||
|
||||
#ui:
|
||||
# appName: exampleAppName # Application's visible name
|
||||
|
|
|
@ -12,7 +12,7 @@ plugins {
|
|||
import com.github.jk1.license.render.*
|
||||
|
||||
group = 'stirling.software'
|
||||
version = '0.23.0'
|
||||
version = '0.23.1'
|
||||
sourceCompatibility = '17'
|
||||
|
||||
repositories {
|
||||
|
@ -127,7 +127,7 @@ dependencies {
|
|||
implementation 'com.twelvemonkeys.imageio:imageio-webp:3.10.1'
|
||||
// implementation 'com.twelvemonkeys.imageio:imageio-xwd:3.10.1'
|
||||
|
||||
implementation 'commons-io:commons-io:2.15.1'
|
||||
implementation 'commons-io:commons-io:2.16.1'
|
||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
|
||||
|
||||
//general PDF
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
apiVersion: v2
|
||||
appVersion: 0.22.8
|
||||
appVersion: 0.23.1
|
||||
description: locally hosted web application that allows you to perform various operations
|
||||
on PDF files
|
||||
home: https://github.com/Stirling-Tools/Stirling-PDF
|
||||
|
|
|
@ -7,18 +7,34 @@ import java.util.Properties;
|
|||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.thymeleaf.spring6.SpringTemplateEngine;
|
||||
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
|
||||
@Configuration
|
||||
@Lazy
|
||||
public class AppConfig {
|
||||
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
name = "system.customHTMLFiles",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) {
|
||||
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
|
||||
templateEngine.addTemplateResolver(new FileFallbackTemplateResolver(resourceLoader));
|
||||
return templateEngine;
|
||||
}
|
||||
|
||||
@Bean(name = "loginEnabled")
|
||||
public boolean loginEnabled() {
|
||||
return applicationProperties.getSecurity().getEnableLogin();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.thymeleaf.IEngineConfiguration;
|
||||
import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver;
|
||||
import org.thymeleaf.templateresource.ClassLoaderTemplateResource;
|
||||
import org.thymeleaf.templateresource.FileTemplateResource;
|
||||
import org.thymeleaf.templateresource.ITemplateResource;
|
||||
|
||||
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
public FileFallbackTemplateResolver(ResourceLoader resourceLoader) {
|
||||
super();
|
||||
this.resourceLoader = resourceLoader;
|
||||
setSuffix(".html");
|
||||
}
|
||||
|
||||
// Note this does not work in local IDE, Prod jar only.
|
||||
@Override
|
||||
protected ITemplateResource computeTemplateResource(
|
||||
IEngineConfiguration configuration,
|
||||
String ownerTemplate,
|
||||
String template,
|
||||
String resourceName,
|
||||
String characterEncoding,
|
||||
Map<String, Object> templateResolutionAttributes) {
|
||||
Resource resource =
|
||||
resourceLoader.getResource("file:./customFiles/templates/" + resourceName);
|
||||
try {
|
||||
if (resource.exists() && resource.isReadable()) {
|
||||
return new FileTemplateResource(resource.getFile().getPath(), characterEncoding);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
|
||||
return new ClassLoaderTemplateResource(
|
||||
Thread.currentThread().getContextClassLoader(),
|
||||
"classpath:/templates/" + resourceName,
|
||||
characterEncoding);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
package stirling.software.SPDF.controller.api.misc;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.image.AffineTransformOp;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
|
@ -33,6 +37,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import io.github.pixee.security.Filenames;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
|
@ -47,12 +52,13 @@ public class FakeScanControllerWIP {
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FakeScanControllerWIP.class);
|
||||
|
||||
//TODO
|
||||
//@PostMapping(consumes = "multipart/form-data", value = "/fake-scan")
|
||||
//@Operation(
|
||||
// summary = "Repair a PDF file",
|
||||
// description =
|
||||
// "This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response.")
|
||||
// TODO finish
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/fake-scan")
|
||||
@Hidden
|
||||
@Operation(
|
||||
summary = "Repair a PDF file",
|
||||
description =
|
||||
"This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response.")
|
||||
public ResponseEntity<byte[]> fakeScan(@ModelAttribute PDFFile request) throws IOException {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
|
||||
|
@ -91,18 +97,19 @@ public class FakeScanControllerWIP {
|
|||
public BufferedImage processImage(BufferedImage image) {
|
||||
// Rotation
|
||||
|
||||
image = rotate(image);
|
||||
// image = softenEdges(image, 5);
|
||||
image = applyGaussianBlur(image, 0.5);
|
||||
addGaussianNoise(image, 0.25);
|
||||
image = linearStretch(image);
|
||||
image = softenEdges(image, 50);
|
||||
image = rotate(image, 1);
|
||||
|
||||
image = applyGaussianBlur(image, 0.5);
|
||||
addGaussianNoise(image, 0.5);
|
||||
image = linearStretch(image);
|
||||
addDustAndHairs(image, 3);
|
||||
return image;
|
||||
}
|
||||
|
||||
private BufferedImage rotate(BufferedImage image) {
|
||||
private BufferedImage rotate(BufferedImage image, double rotation) {
|
||||
|
||||
double rotationRequired = Math.toRadians(1.0);
|
||||
double rotationRequired = Math.toRadians(rotation);
|
||||
double locationX = image.getWidth() / 2;
|
||||
double locationY = image.getHeight() / 2;
|
||||
AffineTransform tx =
|
||||
|
@ -144,39 +151,106 @@ public class FakeScanControllerWIP {
|
|||
BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
Graphics2D g2 = output.createGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2.setRenderingHint(
|
||||
RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
|
||||
g2.drawImage(image, 0, 0, null);
|
||||
g2.setComposite(AlphaComposite.DstIn);
|
||||
g2.setPaint(
|
||||
new GradientPaint(
|
||||
0, 0, new Color(0, 0, 0, 1f), 0, featherRadius, new Color(0, 0, 0, 0f)));
|
||||
g2.fillRect(0, 0, width, featherRadius); // top edge
|
||||
|
||||
// Top edge
|
||||
g2.setPaint(
|
||||
new GradientPaint(
|
||||
0,
|
||||
height - featherRadius,
|
||||
0,
|
||||
new Color(0, 0, 0, 1f),
|
||||
0,
|
||||
featherRadius * 2,
|
||||
new Color(0, 0, 0, 0f)));
|
||||
g2.fillRect(0, 0, width, featherRadius);
|
||||
|
||||
// Bottom edge
|
||||
g2.setPaint(
|
||||
new GradientPaint(
|
||||
0,
|
||||
height - featherRadius * 2,
|
||||
new Color(0, 0, 0, 0f),
|
||||
0,
|
||||
height,
|
||||
new Color(0, 0, 0, 1f)));
|
||||
g2.fillRect(0, height - featherRadius, width, featherRadius); // bottom edge
|
||||
g2.fillRect(0, height - featherRadius, width, featherRadius);
|
||||
|
||||
// Left edge
|
||||
g2.setPaint(
|
||||
new GradientPaint(
|
||||
0, 0, new Color(0, 0, 0, 1f), featherRadius, 0, new Color(0, 0, 0, 0f)));
|
||||
g2.fillRect(0, 0, featherRadius, height); // left edge
|
||||
0,
|
||||
0,
|
||||
new Color(0, 0, 0, 1f),
|
||||
featherRadius * 2,
|
||||
0,
|
||||
new Color(0, 0, 0, 0f)));
|
||||
g2.fillRect(0, 0, featherRadius, height);
|
||||
|
||||
// Right edge
|
||||
g2.setPaint(
|
||||
new GradientPaint(
|
||||
width - featherRadius,
|
||||
width - featherRadius * 2,
|
||||
0,
|
||||
new Color(0, 0, 0, 0f),
|
||||
width,
|
||||
0,
|
||||
new Color(0, 0, 0, 1f)));
|
||||
g2.fillRect(width - featherRadius, 0, featherRadius, height); // right edge
|
||||
g2.fillRect(width - featherRadius, 0, featherRadius, height);
|
||||
|
||||
g2.dispose();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private void addDustAndHairs(BufferedImage image, float intensity) {
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
Random random = new SecureRandom();
|
||||
|
||||
// Set rendering hints for better quality
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// Calculate the number of artifacts based on intensity
|
||||
int numSpots = (int) (intensity * 10);
|
||||
int numHairs = (int) (intensity * 20);
|
||||
|
||||
// Add spots with more variable sizes
|
||||
g2d.setColor(new Color(100, 100, 100, 50)); // Semi-transparent gray
|
||||
for (int i = 0; i < numSpots; i++) {
|
||||
int x = random.nextInt(width);
|
||||
int y = random.nextInt(height);
|
||||
int ovalSize = 1 + random.nextInt(3); // Base size + variable component
|
||||
if (random.nextFloat() > 0.9) {
|
||||
// 10% chance to get a larger spot
|
||||
ovalSize += random.nextInt(3);
|
||||
}
|
||||
g2d.fill(new Ellipse2D.Double(x, y, ovalSize, ovalSize));
|
||||
}
|
||||
|
||||
// Add hairs
|
||||
g2d.setStroke(new BasicStroke(0.5f)); // Thin stroke for hairs
|
||||
g2d.setColor(new Color(80, 80, 80, 40)); // Slightly lighter and more transparent
|
||||
for (int i = 0; i < numHairs; i++) {
|
||||
int x1 = random.nextInt(width);
|
||||
int y1 = random.nextInt(height);
|
||||
int x2 = x1 + random.nextInt(20) - 10; // Random length and direction
|
||||
int y2 = y1 + random.nextInt(20) - 10;
|
||||
Path2D.Double hair = new Path2D.Double();
|
||||
hair.moveTo(x1, y1);
|
||||
hair.curveTo(x1, y1, (x1 + x2) / 2, (y1 + y2) / 2, x2, y2);
|
||||
g2d.draw(hair);
|
||||
}
|
||||
|
||||
g2d.dispose();
|
||||
}
|
||||
|
||||
private void addGaussianNoise(BufferedImage image, double strength) {
|
||||
Random rand = new SecureRandom();
|
||||
int width = image.getWidth();
|
||||
|
|
|
@ -20,12 +20,10 @@ import org.apache.pdfbox.printing.PDFPageable;
|
|||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.api.misc.PrintFileRequest;
|
||||
|
@ -35,12 +33,13 @@ import stirling.software.SPDF.model.api.misc.PrintFileRequest;
|
|||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||
public class PrintFileController {
|
||||
|
||||
//TODO
|
||||
//@PostMapping(value = "/print-file", consumes = "multipart/form-data")
|
||||
//@Operation(
|
||||
// TODO
|
||||
// @PostMapping(value = "/print-file", consumes = "multipart/form-data")
|
||||
// @Operation(
|
||||
// summary = "Prints PDF/Image file to a set printer",
|
||||
// description =
|
||||
// "Input of PDF or Image along with a printer name/URL/IP to match against to send it to (Fire and forget) Input:Any Output:N/A Type:SISO")
|
||||
// "Input of PDF or Image along with a printer name/URL/IP to match against to
|
||||
// send it to (Fire and forget) Input:Any Output:N/A Type:SISO")
|
||||
public ResponseEntity<String> printFile(@ModelAttribute PrintFileRequest request)
|
||||
throws IOException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
|
|
|
@ -212,6 +212,15 @@ public class ApplicationProperties {
|
|||
private Integer maxFileSize;
|
||||
private boolean showUpdate;
|
||||
private Boolean showUpdateOnlyAdmin;
|
||||
private boolean customHTMLFiles;
|
||||
|
||||
public boolean isCustomHTMLFiles() {
|
||||
return customHTMLFiles;
|
||||
}
|
||||
|
||||
public void setCustomHTMLFiles(boolean customHTMLFiles) {
|
||||
this.customHTMLFiles = customHTMLFiles;
|
||||
}
|
||||
|
||||
public boolean getShowUpdateOnlyAdmin() {
|
||||
return showUpdateOnlyAdmin;
|
||||
|
|
|
@ -342,8 +342,6 @@ public class PdfUtils {
|
|||
boolean imageIsLandscape = image.getWidth() > image.getHeight();
|
||||
PDRectangle pageSize = PDRectangle.A4;
|
||||
|
||||
System.out.println(fitOption);
|
||||
|
||||
if (autoRotate && imageIsLandscape) {
|
||||
pageSize = new PDRectangle(pageSize.getHeight(), pageSize.getWidth());
|
||||
}
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF إلى PDF / A
|
|||
pdfToPDFA.credit=تستخدم هذه الخدمة OCRmyPDF لتحويل PDF / A.
|
||||
pdfToPDFA.submit=تحويل
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF към PDF/A
|
|||
pdfToPDFA.credit=Тази услуга използва OCRmyPDF за PDF/A преобразуване.
|
||||
pdfToPDFA.submit=Преобразуване
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF a PDF/A
|
|||
pdfToPDFA.credit=Utilitza OCRmyPDF per la conversió a PDF/A
|
||||
pdfToPDFA.submit=Converteix
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF zu PDF/A
|
|||
pdfToPDFA.credit=Dieser Dienst verwendet OCRmyPDF für die PDF/A-Konvertierung
|
||||
pdfToPDFA.submit=Konvertieren
|
||||
pdfToPDFA.tip=Dieser Dienst kann nur einzelne Eingangsdateien verarbeiten.
|
||||
pdfToPDFA.outputFormat=Ausgabeformat
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF σε PDF/A
|
|||
pdfToPDFA.credit=Αυτή η υπηρεσία χρησιμοποιεί OCRmyPDF για PDF/A μετατροπή
|
||||
pdfToPDFA.submit=Μετατροπή
|
||||
pdfToPDFA.tip=Προς το παρόν δεν λειτουργεί για πολλαπλές εισόδους ταυτόχρονα
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF To PDF/A
|
|||
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
||||
pdfToPDFA.submit=Convert
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF To PDF/A
|
|||
pdfToPDFA.credit=This service uses OCRmyPDF for PDF/A conversion
|
||||
pdfToPDFA.submit=Convert
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF a PDF/A
|
|||
pdfToPDFA.credit=Este servicio usa OCRmyPDF para la conversión a PDF/A
|
||||
pdfToPDFA.submit=Convertir
|
||||
pdfToPDFA.tip=Actualmente no funciona para múltiples entrada a la vez
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDFa PDF/A bihurtu
|
|||
pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko
|
||||
pdfToPDFA.submit=Bihurtu
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF en PDF/A
|
|||
pdfToPDFA.credit=Ce service utilise OCRmyPDF pour la conversion en PDF/A.
|
||||
pdfToPDFA.submit=Convertir
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF से PDF/A में
|
|||
pdfToPDFA.credit=इस सेवा में PDF/A परिवर्तन के लिए OCRmyPDF का उपयोग किया जाता है।
|
||||
pdfToPDFA.submit=परिवर्तित करें
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF >> PDF/A
|
|||
pdfToPDFA.credit=Ez a szolgáltatás az OCRmyPDF-t használja a PDF/A konverzióhoz
|
||||
pdfToPDFA.submit=Konvertálás
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF ke PDF/A
|
|||
pdfToPDFA.credit=Layanan ini menggunakan OCRmyPDF untuk konversi PDF/A.
|
||||
pdfToPDFA.submit=Konversi
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -646,7 +646,7 @@ removeBlanks.submit=Rimuovi
|
|||
|
||||
#removeAnnotations
|
||||
removeAnnotations.title=Rimuovi Annotazioni
|
||||
removeAnnotations.header=Remuovi Annotazioni
|
||||
removeAnnotations.header=Rimuovi Annotazioni
|
||||
removeAnnotations.submit=Rimuovi
|
||||
|
||||
|
||||
|
@ -941,6 +941,7 @@ pdfToPDFA.header=Da PDF a PDF/A
|
|||
pdfToPDFA.credit=Questo servizio utilizza OCRmyPDF per la conversione in PDF/A.
|
||||
pdfToPDFA.submit=Converti
|
||||
pdfToPDFA.tip=Attualmente non funziona per più input contemporaneamente
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDFをPDF/Aに変換
|
|||
pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用しています。
|
||||
pdfToPDFA.submit=変換
|
||||
pdfToPDFA.tip=現在、一度に複数の入力に対して機能しません
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF 문서를 PDF/A로 변환
|
|||
pdfToPDFA.credit=이 서비스는 PDF/A 변환을 위해 OCRmyPDF 문서를 사용합니다.
|
||||
pdfToPDFA.submit=변환
|
||||
pdfToPDFA.tip=현재 한 번에 여러 입력에 대해 작동하지 않습니다.
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF naar PDF/A
|
|||
pdfToPDFA.credit=Deze service gebruikt OCRmyPDF voor PDF/A-conversie
|
||||
pdfToPDFA.submit=Converteren
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF na PDF/A
|
|||
pdfToPDFA.credit=Ta usługa używa OCRmyPDF do konwersji PDF/A
|
||||
pdfToPDFA.submit=Konwertuj
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF para PDF/A
|
|||
pdfToPDFA.credit=Este serviço usa OCRmyPDF para Conversão de PDF/A
|
||||
pdfToPDFA.submit=Converter
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF para PDF/A
|
|||
pdfToPDFA.credit=Este serviço usa OCRmyPDF para Conversão de PDF/A
|
||||
pdfToPDFA.submit=Converter
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF către PDF/A
|
|||
pdfToPDFA.credit=Acest serviciu utilizează OCRmyPDF pentru conversia în PDF/A
|
||||
pdfToPDFA.submit=Convert
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF в PDF/A
|
|||
pdfToPDFA.credit=Этот сервис использует OCRmyPDF для преобразования PDF/A
|
||||
pdfToPDFA.submit=Конвертировать
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF u PDF/A
|
|||
pdfToPDFA.credit=Ova usluga koristi OCRmyPDF za konverziju u PDF/A format
|
||||
pdfToPDFA.submit=Konvertuj
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF till PDF/A
|
|||
pdfToPDFA.credit=Denna tjänst använder OCRmyPDF för PDF/A-konvertering
|
||||
pdfToPDFA.submit=Konvertera
|
||||
pdfToPDFA.tip=Currently does not work for multiple inputs at once
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -66,7 +66,7 @@ seeDockerHub=Docker Hub'a bakın
|
|||
visitGithub=Github Deposunu Ziyaret Edin
|
||||
donate=Bağış Yapın
|
||||
color=Renk
|
||||
sponsor=Sponsor
|
||||
sponsor=Bağış
|
||||
|
||||
|
||||
|
||||
|
@ -112,7 +112,7 @@ navbar.settings=Ayarlar
|
|||
#############
|
||||
settings.title=Ayarlar
|
||||
settings.update=Güncelleme mevcut
|
||||
settings.updateAvailable={0} is the current installed version. A new version ({1}) is available.
|
||||
settings.updateAvailable={0} mevcut kurulu sürümdür. Yeni bir sürüm ({1}) mevcuttur.
|
||||
settings.appVersion=Uygulama Sürümü:
|
||||
settings.downloadOption.title=İndirme seçeneği seçin (Zip olmayan tek dosya indirmeler için):
|
||||
settings.downloadOption.1=Aynı pencerede aç
|
||||
|
@ -666,7 +666,7 @@ BookToPDF.submit=Dönüştür
|
|||
#PDFToBook
|
||||
PDFToBook.title=PDF'den Kitaba
|
||||
PDFToBook.header=PDF'den Kitaba
|
||||
PDFToBook.selectText.1=Format
|
||||
PDFToBook.selectText.1=Format biçimi
|
||||
PDFToBook.credit=Kalibre Kullanır
|
||||
PDFToBook.submit=Dönüştür
|
||||
|
||||
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF'den PDF/A'ya
|
|||
pdfToPDFA.credit=Bu hizmet PDF/A dönüşümü için OCRmyPDF kullanır
|
||||
pdfToPDFA.submit=Dönüştür
|
||||
pdfToPDFA.tip=Şu anda aynı anda birden fazla giriş için çalışmıyor
|
||||
pdfToPDFA.outputFormat=Çıkış formatı
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF в PDF/A
|
|||
pdfToPDFA.credit=Цей сервіс використовує OCRmyPDF для перетворення у формат PDF/A
|
||||
pdfToPDFA.submit=Конвертувати
|
||||
pdfToPDFA.tip=Наразі не працює для кількох вхідних файлів одночасно
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF转换为PDF/A
|
|||
pdfToPDFA.credit=此服务使用OCRmyPDF进行PDF/A转换
|
||||
pdfToPDFA.submit=转换
|
||||
pdfToPDFA.tip=目前不支持上传多个
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -941,6 +941,7 @@ pdfToPDFA.header=PDF 轉 PDF/A
|
|||
pdfToPDFA.credit=此服務使用 OCRmyPDF 進行 PDF/A 轉換
|
||||
pdfToPDFA.submit=轉換
|
||||
pdfToPDFA.tip=目前不支援上傳多個
|
||||
pdfToPDFA.outputFormat=Output format
|
||||
|
||||
|
||||
#PDFToWord
|
||||
|
|
|
@ -14,7 +14,8 @@ system:
|
|||
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
|
||||
showUpdate: true # see when a new update is available
|
||||
showUpdateOnlyAdmin: false # Only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
|
||||
|
||||
customHTMLFiles: false # Enable to have files placed in /customFiles/templates override the existing template html files
|
||||
|
||||
#ui:
|
||||
# appName: exampleAppName # Application's visible name
|
||||
# homeDescription: I am a description # Short description or tagline shown on homepage.
|
||||
|
|
|
@ -17,20 +17,20 @@
|
|||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto flex-nowrap">
|
||||
<li class="nav-item">
|
||||
<li class="nav-item" th:if="${@endpointConfiguration.isEndpointEnabled('multi-tool')}">
|
||||
<a class="nav-link" href="#" th:href="@{multi-tool}" th:classappend="${currentPage}=='multi-tool' ? 'active' : ''" th:title="#{home.multiTool.desc}">
|
||||
<img class="icon" src="images/tools.svg" alt="icon">
|
||||
<span class="icon-text" th:text="#{home.multiTool.title}"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item nav-item-separator"></li>
|
||||
<li class="nav-item">
|
||||
<li th:if="${@endpointConfiguration.isEndpointEnabled('multi-tool')}" class="nav-item nav-item-separator"></li>
|
||||
<li th:if="${@endpointConfiguration.isEndpointEnabled('pipeline')}" class="nav-item">
|
||||
<a class="nav-link" href="#" th:href="@{pipeline}" th:classappend="${currentPage}=='pipeline' ? 'active' : ''" th:title="#{home.pipeline.desc}">
|
||||
<img class="icon" src="images/pipeline.svg" alt="icon">
|
||||
<span class="icon-text" th:text="#{home.pipeline.title}"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item nav-item-separator"></li>
|
||||
<li th:if="${@endpointConfiguration.isEndpointEnabled('pipeline')}" class="nav-item nav-item-separator"></li>
|
||||
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='crop' OR ${currentPage}=='adjust-contrast' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' OR ${currentPage}=='multi-page-layout' OR ${currentPage}=='scale-pages' OR ${currentPage}=='auto-split-pdf' OR ${currentPage}=='extract-page' OR ${currentPage}=='pdf-to-single-page' ? 'active' : ''">
|
||||
<a class="nav-link dropdown-toggle" id="navbarDropdown-1" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<img class="icon" src="images/file-earmark-pdf.svg" alt="icon">
|
||||
|
@ -211,7 +211,7 @@
|
|||
<span id="zipThresholdValue" class="ms-2"></span>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input"id="boredWaiting" th:title="#{settings.bored.help}">
|
||||
<input type="checkbox" class="form-check-input" id="boredWaiting" th:title="#{settings.bored.help}">
|
||||
<label class="form-check-label" for="boredWaiting" th:text="#{bored}"></label>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
const defaultLocale = document.documentElement.getAttribute('language') || 'en_GB';
|
||||
const defaultLocale = document.documentElement.getAttribute('data-language') || 'en_GB';
|
||||
const storedLocale = localStorage.getItem('languageCode') || defaultLocale;
|
||||
|
||||
const currentURL = new URL(window.location.href);
|
||||
|
|
Loading…
Reference in New Issue