[V2] feat(convert): add PDF/X export option (#5285)

# Description of Changes

This pull request adds support for converting PDF files to PDF/X format
in the frontend, alongside the existing PDF/A conversion. The changes
include UI updates, translation strings, configuration, and processing
logic to enable PDF to PDF/X conversion using the same backend endpoint
as PDF/A, with appropriate user options and warnings.

**PDF/X Conversion Support:**

- Added a new `ConvertToPdfxSettings` component for configuring PDF/X
conversion options, including output format selection and digital
signature warnings.
(`frontend/src/core/components/tools/convert/ConvertToPdfxSettings.tsx`)
- Updated the conversion settings UI to display PDF/X options when
converting from PDF to PDF/X.
(`frontend/src/core/components/tools/convert/ConvertSettings.tsx`)

**Configuration and Processing Logic:**

- Extended conversion constants and parameters to recognize PDF/X as a
target format, map it to the PDF/A backend endpoint, and ensure correct
file naming and processing behavior.
(`frontend/src/core/constants/convertConstants.ts`,
`frontend/src/core/hooks/tools/convert/useConvertOperation.ts`,
`frontend/src/core/hooks/tools/convert/useConvertParameters.ts`)
- Ensured that PDF/X conversions are processed separately per file,
similar to PDF/A.
(`frontend/src/core/hooks/tools/convert/useConvertOperation.ts`)

**UI and Translation Updates:**

- Updated translation strings to include PDF/X options, descriptions,
and warnings. (`frontend/public/locales/en-GB/translation.toml`)

<img width="366" height="998" alt="image"
src="https://github.com/user-attachments/assets/b28fa095-9350-4db2-a0b5-bddcf003fa46"
/>


<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
This commit is contained in:
Balázs Szücs
2026-01-23 16:50:39 +01:00
committed by GitHub
parent 039e3b5fa8
commit 4d84dcdd42
10 changed files with 145 additions and 22 deletions

View File

@@ -479,15 +479,22 @@ public class ConvertPDFToPDFA {
command.add("-dCompatibilityLevel=" + profile.getCompatibilityLevel());
command.add("-sDEVICE=pdfwrite");
command.add("-sColorConversionStrategy=RGB");
command.add("-dProcessColorModel=/DeviceRGB");
command.add("-sOutputICCProfile=" + colorProfiles.rgb().toAbsolutePath());
command.add("-sDefaultRGBProfile=" + colorProfiles.rgb().toAbsolutePath());
command.add("-sDefaultGrayProfile=" + colorProfiles.gray().toAbsolutePath());
command.add("-dEmbedAllFonts=true");
command.add("-dSubsetFonts=false"); // Embed complete fonts to avoid incomplete glyphs
command.add("-dSubsetFonts=true");
command.add("-dCompressFonts=true");
command.add("-dNOSUBSTFONTS=false"); // Allow font substitution for problematic fonts
command.add("-dPDFSETTINGS=/prepress");
// Explicitly tune downsampling/compression for high-quality print
command.add("-dColorImageDownsampleType=/Bicubic");
command.add("-dColorImageResolution=300");
command.add("-dGrayImageDownsampleType=/Bicubic");
command.add("-dGrayImageResolution=300");
command.add("-dMonoImageDownsampleType=/Bicubic");
command.add("-dMonoImageResolution=1200");
command.add("-dNOPAUSE");
command.add("-dBATCH");
command.add("-dNOOUTERSAVE");
@@ -2445,9 +2452,7 @@ public class ConvertPDFToPDFA {
@Getter
private enum PdfXProfile {
PDF_X_1("PDF/X-1", "_PDFX-1.pdf", "1.3", "2001", "pdfx-1", "pdfx"),
PDF_X_3("PDF/X-3", "_PDFX-3.pdf", "1.3", "2003", "pdfx-3"),
PDF_X_4("PDF/X-4", "_PDFX-4.pdf", "1.4", "2008", "pdfx-4");
PDF_X("PDF/X", "_PDFX.pdf", "1.6", "2008", "pdfx");
private final String displayName;
private final String suffix;
@@ -2473,7 +2478,7 @@ public class ConvertPDFToPDFA {
static PdfXProfile fromRequest(String requestToken) {
if (requestToken == null) {
return PDF_X_4;
return PDF_X;
}
String normalized = requestToken.trim().toLowerCase(Locale.ROOT);
Optional<PdfXProfile> match =
@@ -2481,7 +2486,7 @@ public class ConvertPDFToPDFA {
.filter(profile -> profile.requestTokens.contains(normalized))
.findFirst();
return match.orElse(PDF_X_4);
return match.orElse(PDF_X);
}
String outputSuffix() {

View File

@@ -273,7 +273,9 @@ public class StampController {
// Split the stampText into multiple lines
String[] lines =
RegexPatternUtils.getInstance().getEscapedNewlinePattern().split(processedStampText);
RegexPatternUtils.getInstance()
.getEscapedNewlinePattern()
.split(processedStampText);
// Calculate dynamic line height based on font ascent and descent
float ascent = font.getFontDescriptor().getAscent();

View File

@@ -14,9 +14,6 @@ public class PdfToPdfARequest extends PDFFile {
@Schema(
description = "The output format type (PDF/A or PDF/X)",
requiredMode = Schema.RequiredMode.REQUIRED,
allowableValues = {
"pdfa", "pdfa-1", "pdfa-2", "pdfa-2b", "pdfa-3", "pdfa-3b", "pdfx", "pdfx-1",
"pdfx-3", "pdfx-4"
})
allowableValues = {"pdfa", "pdfa-1", "pdfa-2", "pdfa-2b", "pdfa-3", "pdfa-3b", "pdfx"})
private String outputFormat;
}