From 182eb504de65e54e6361df2ce709f9ad6811b156 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20Sz=C3=BCcs?=
<127139797+balazs-szucs@users.noreply.github.com>
Date: Sat, 27 Dec 2025 02:32:55 +0100
Subject: [PATCH] [V2] feat(convert): add support for CBR to PDF and PDF to CBR
conversions (#4833)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Description of Changes
TLDR:
- Introduced `ConvertFromCbrSettings` and `ConvertToCbrSettings`
components for handling conversion-specific settings.
- Updated `ConvertSettings` to include CBR-related configurations.
- Updated `useConvertParameters` with new parameters: `cbrOptions` and
`pdfToCbrOptions`.
- Updated locales with CBR-related translations.
- Added endpoints and updated conversion matrix for CBR formats in
`convertConstants`.
- Modified `useConvertOperation` to handle CBR-specific parameters
during form data preparation.
For backend see this PR: #4581
This pull request adds support for converting between CBR (Comic Book
Archive) and PDF formats in the frontend. It introduces new UI
components for configuring conversion options, updates the conversion
constants and logic, and ensures parameters for these conversions are
handled correctly throughout the app.
**CBR/PDF Conversion Features:**
* Added new UI components: `ConvertFromCbrSettings` for CBR to PDF
conversions (option to optimize for ebook readers), and
`ConvertToCbrSettings` for PDF to CBR conversions (DPI selection for
image rendering). These are conditionally rendered in
`ConvertSettings.tsx` based on selected formats.
**Conversion Logic and Constants:**
* Extended conversion endpoints, format options, conversion matrix, and
endpoint mappings to support CBR to PDF and PDF to CBR conversions.
* Updated `shouldProcessFilesSeparately` logic to handle PDF to CBR
conversions, ensuring each PDF generates its own archive.
**Parameter Handling:**
* Added new parameters (`cbrOptions` and `pdfToCbrOptions`) to the
conversion parameter interface and default values, ensuring they are
set/reset appropriately during format changes
* Modified form data construction to include new options for CBR/PDF
conversions (optimize for ebook, DPI).
### Frontend
Note on RAR5. You can go back-and-forth with this converter due to the
fact on default pdf to cbr makes RAR5 meanwhile, cbr to pdf can only
RAR4 and below. This is unfortunate limitation of JunRAR library. In the
real world, generally RAR5s are not that common, and they mostly
unsupported by open-source software.
---
## Checklist
### General
- [X] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [X] 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)
- [X] I have performed a self-review of my own code
- [X] 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)
- [X] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [X] 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
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
Co-authored-by: Reece Browne <74901996+reecebrowne@users.noreply.github.com>
---
.../public/locales/en-GB/translation.toml | 3 +
.../fileEditor/FileEditorThumbnail.tsx | 5 +-
.../components/fileManager/FileListItem.tsx | 7 +-
.../tools/convert/ConvertFromCbrSettings.tsx | 36 ++++++++++
.../tools/convert/ConvertSettings.tsx | 38 ++++++++++
.../tools/convert/ConvertToCbrSettings.tsx | 39 ++++++++++
.../src/core/constants/convertConstants.ts | 11 ++-
.../core/constants/convertSupportedFornats.ts | 2 +-
.../tools/convert/useConvertOperation.ts | 8 ++-
.../tools/convert/useConvertParameters.ts | 12 ++++
.../tests/convert/ConvertIntegration.test.tsx | 72 +++++++++++++++++++
frontend/src/core/utils/urlMapping.ts | 2 +
12 files changed, 229 insertions(+), 6 deletions(-)
create mode 100644 frontend/src/core/components/tools/convert/ConvertFromCbrSettings.tsx
create mode 100644 frontend/src/core/components/tools/convert/ConvertToCbrSettings.tsx
diff --git a/frontend/public/locales/en-GB/translation.toml b/frontend/public/locales/en-GB/translation.toml
index e9d008535..f9e13f3c1 100644
--- a/frontend/public/locales/en-GB/translation.toml
+++ b/frontend/public/locales/en-GB/translation.toml
@@ -1278,6 +1278,9 @@ cbzOptions = "CBZ to PDF Options"
optimizeForEbook = "Optimize PDF for ebook readers (uses Ghostscript)"
cbzOutputOptions = "PDF to CBZ Options"
cbzDpi = "DPI for image rendering"
+cbrOptions = "CBR Options"
+cbrOutputOptions = "PDF to CBR Options"
+cbrDpi = "DPI for image rendering"
[convert.ebookOptions]
ebookOptions = "eBook to PDF Options"
diff --git a/frontend/src/core/components/fileEditor/FileEditorThumbnail.tsx b/frontend/src/core/components/fileEditor/FileEditorThumbnail.tsx
index 32ad10840..953bd018f 100644
--- a/frontend/src/core/components/fileEditor/FileEditorThumbnail.tsx
+++ b/frontend/src/core/components/fileEditor/FileEditorThumbnail.tsx
@@ -112,6 +112,7 @@ const FileEditorThumbnail = ({
}, [file.name]);
const isCBZ = extLower === 'cbz';
+ const isCBR = extLower === 'cbr';
const pageLabel = useMemo(
() =>
@@ -226,7 +227,7 @@ const FileEditorThumbnail = ({
alert({ alertType: 'success', title: `Unzipping ${file.name}`, expandable: false, durationMs: 2500 });
}
},
- hidden: !isZipFile || !onUnzipFile || isCBZ,
+ hidden: !isZipFile || !onUnzipFile || isCBZ || isCBR,
},
{
id: 'close',
@@ -238,7 +239,7 @@ const FileEditorThumbnail = ({
},
color: 'red',
}
- ], [t, file.id, file.name, isZipFile, onViewFile, onDownloadFile, onUnzipFile, handleCloseWithConfirmation]);
+ ], [t, file.id, file.name, isZipFile, isCBR, onViewFile, onDownloadFile, onUnzipFile, handleCloseWithConfirmation]);
// ---- Card interactions ----
const handleCardClick = () => {
diff --git a/frontend/src/core/components/fileManager/FileListItem.tsx b/frontend/src/core/components/fileManager/FileListItem.tsx
index 94da35af5..87b458e10 100644
--- a/frontend/src/core/components/fileManager/FileListItem.tsx
+++ b/frontend/src/core/components/fileManager/FileListItem.tsx
@@ -52,6 +52,11 @@ const FileListItem: React.FC = ({
// Check if this is a ZIP file
const isZipFile = zipFileService.isZipFileStub(file);
+ // Check file extension
+ const extLower = (file.name?.match(/\.([a-z0-9]+)$/i)?.[1] || '').toLowerCase();
+ const isCBZ = extLower === 'cbz';
+ const isCBR = extLower === 'cbr';
+
// Keep item in hovered state if menu is open
const shouldShowHovered = isHovered || isMenuOpen;
@@ -240,7 +245,7 @@ const FileListItem: React.FC = ({
)}
{/* Unzip option for ZIP files */}
- {isZipFile && !isHistoryFile && (
+ {isZipFile && !isHistoryFile && !isCBZ && !isCBR && (
<>
}
diff --git a/frontend/src/core/components/tools/convert/ConvertFromCbrSettings.tsx b/frontend/src/core/components/tools/convert/ConvertFromCbrSettings.tsx
new file mode 100644
index 000000000..8f1a80946
--- /dev/null
+++ b/frontend/src/core/components/tools/convert/ConvertFromCbrSettings.tsx
@@ -0,0 +1,36 @@
+import { Stack, Text, Checkbox } from '@mantine/core';
+import { useTranslation } from 'react-i18next';
+import { ConvertParameters } from "@app/hooks/tools/convert/useConvertParameters";
+
+interface ConvertFromCbrSettingsProps {
+ parameters: ConvertParameters;
+ onParameterChange: (key: K, value: ConvertParameters[K]) => void;
+ disabled?: boolean;
+}
+
+const ConvertFromCbrSettings = ({
+ parameters,
+ onParameterChange,
+ disabled = false
+}: ConvertFromCbrSettingsProps) => {
+ const { t } = useTranslation();
+
+ return (
+
+ {t("convert.cbrOptions", "CBR Options")}:
+
+ onParameterChange('cbrOptions', {
+ ...parameters.cbrOptions,
+ optimizeForEbook: event.currentTarget.checked
+ })}
+ disabled={disabled}
+ data-testid="optimize-ebook-checkbox"
+ />
+
+ );
+};
+
+export default ConvertFromCbrSettings;
diff --git a/frontend/src/core/components/tools/convert/ConvertSettings.tsx b/frontend/src/core/components/tools/convert/ConvertSettings.tsx
index c31928112..127fbb13c 100644
--- a/frontend/src/core/components/tools/convert/ConvertSettings.tsx
+++ b/frontend/src/core/components/tools/convert/ConvertSettings.tsx
@@ -17,6 +17,8 @@ import ConvertFromEmailSettings from "@app/components/tools/convert/ConvertFromE
import ConvertFromCbzSettings from "@app/components/tools/convert/ConvertFromCbzSettings";
import ConvertToCbzSettings from "@app/components/tools/convert/ConvertToCbzSettings";
import ConvertToPdfaSettings from "@app/components/tools/convert/ConvertToPdfaSettings";
+import ConvertFromCbrSettings from "@app/components/tools/convert/ConvertFromCbrSettings";
+import ConvertToCbrSettings from "@app/components/tools/convert/ConvertToCbrSettings";
import ConvertFromEbookSettings from "@app/components/tools/convert/ConvertFromEbookSettings";
import { ConvertParameters } from "@app/hooks/tools/convert/useConvertParameters";
import {
@@ -143,6 +145,12 @@ const ConvertSettings = ({
onParameterChange('pdfaOptions', {
outputFormat: 'pdfa-1',
});
+ onParameterChange('cbrOptions', {
+ optimizeForEbook: false,
+ });
+ onParameterChange('pdfToCbrOptions', {
+ dpi: 150,
+ });
onParameterChange('cbzOptions', {
optimizeForEbook: false,
});
@@ -217,6 +225,12 @@ const ConvertSettings = ({
onParameterChange('pdfaOptions', {
outputFormat: 'pdfa-1',
});
+ onParameterChange('cbrOptions', {
+ optimizeForEbook: false,
+ });
+ onParameterChange('pdfToCbrOptions', {
+ dpi: 150,
+ });
onParameterChange('cbzOptions', {
optimizeForEbook: false,
});
@@ -385,6 +399,30 @@ const ConvertSettings = ({
>
)}
+ {/* CBR to PDF options */}
+ {parameters.fromExtension === 'cbr' && parameters.toExtension === 'pdf' && (
+ <>
+
+
+ >
+ )}
+
+ {/* PDF to CBR options */}
+ {parameters.fromExtension === 'pdf' && parameters.toExtension === 'cbr' && (
+ <>
+
+
+ >
+ )}
+
);
};
diff --git a/frontend/src/core/components/tools/convert/ConvertToCbrSettings.tsx b/frontend/src/core/components/tools/convert/ConvertToCbrSettings.tsx
new file mode 100644
index 000000000..db85eda77
--- /dev/null
+++ b/frontend/src/core/components/tools/convert/ConvertToCbrSettings.tsx
@@ -0,0 +1,39 @@
+import { Stack, Text, NumberInput } from "@mantine/core";
+import { useTranslation } from "react-i18next";
+import { ConvertParameters } from "@app/hooks/tools/convert/useConvertParameters";
+
+interface ConvertToCbrSettingsProps {
+ parameters: ConvertParameters;
+ onParameterChange: (key: K, value: ConvertParameters[K]) => void;
+ disabled?: boolean;
+}
+
+const ConvertToCbrSettings = ({
+ parameters,
+ onParameterChange,
+ disabled = false
+}: ConvertToCbrSettingsProps) => {
+ const { t } = useTranslation();
+
+ return (
+
+ {t("convert.cbrOutputOptions", "PDF to CBR Options")}:
+
+
+ typeof val === 'number' &&
+ onParameterChange('pdfToCbrOptions', { ...parameters.pdfToCbrOptions, dpi: val })
+ }
+ min={72}
+ max={600}
+ step={50}
+ disabled={disabled}
+ />
+
+ );
+};
+
+export default ConvertToCbrSettings;
diff --git a/frontend/src/core/constants/convertConstants.ts b/frontend/src/core/constants/convertConstants.ts
index 80e205967..0ffe5783f 100644
--- a/frontend/src/core/constants/convertConstants.ts
+++ b/frontend/src/core/constants/convertConstants.ts
@@ -34,6 +34,8 @@ export const CONVERSION_ENDPOINTS = {
'html-pdf': '/api/v1/convert/html/pdf',
'markdown-pdf': '/api/v1/convert/markdown/pdf',
'eml-pdf': '/api/v1/convert/eml/pdf',
+ 'cbr-pdf': '/api/v1/convert/cbr/pdf',
+ 'pdf-cbr': '/api/v1/convert/pdf/cbr',
'ebook-pdf': '/api/v1/convert/ebook/pdf',
'pdf-text-editor': '/api/v1/convert/pdf/text-editor',
'text-editor-pdf': '/api/v1/convert/text-editor/pdf'
@@ -57,6 +59,8 @@ export const ENDPOINT_NAMES = {
'markdown-pdf': 'markdown-to-pdf',
'eml-pdf': 'eml-to-pdf',
'ebook-pdf': 'ebook-to-pdf',
+ 'cbr-pdf': 'cbr-to-pdf',
+ 'pdf-cbr': 'pdf-to-cbr',
'pdf-text-editor': 'pdf-to-text-editor',
'text-editor-pdf': 'text-editor-to-pdf'
} as const;
@@ -68,6 +72,7 @@ export const FROM_FORMAT_OPTIONS = [
{ value: 'image', label: 'Images', group: 'Multiple Files' },
{ value: 'pdf', label: 'PDF', group: 'Document' },
{ value: 'cbz', label: 'CBZ', group: 'Archive' },
+ { value: 'cbr', label: 'CBR', group: 'Archive' },
{ value: 'docx', label: 'DOCX', group: 'Document' },
{ value: 'doc', label: 'DOC', group: 'Document' },
{ value: 'odt', label: 'ODT', group: 'Document' },
@@ -103,6 +108,7 @@ export const TO_FORMAT_OPTIONS = [
{ value: 'docx', label: 'DOCX', group: 'Document' },
{ value: 'odt', label: 'ODT', group: 'Document' },
{ value: 'cbz', label: 'CBZ', group: 'Archive' },
+ { value: 'cbr', label: 'CBR', group: 'Archive' },
{ value: 'csv', label: 'CSV', group: 'Spreadsheet' },
{ value: 'pptx', label: 'PPTX', group: 'Presentation' },
{ value: 'odp', label: 'ODP', group: 'Presentation' },
@@ -123,7 +129,7 @@ export const TO_FORMAT_OPTIONS = [
export const CONVERSION_MATRIX: Record = {
'any': ['pdf'], // Mixed files always convert to PDF
'image': ['pdf'], // Multiple images always convert to PDF
- 'pdf': ['png', 'jpg', 'gif', 'tiff', 'bmp', 'webp', 'docx', 'odt', 'pptx', 'odp', 'csv', 'txt', 'rtf', 'md', 'html', 'xml', 'pdfa', 'cbz'],
+ 'pdf': ['png', 'jpg', 'gif', 'tiff', 'bmp', 'webp', 'docx', 'odt', 'pptx', 'odp', 'csv', 'txt', 'rtf', 'md', 'html', 'xml', 'pdfa', 'cbz', 'cbr'],
'cbz': ['pdf'],
'docx': ['pdf'], 'doc': ['pdf'], 'odt': ['pdf'],
'xlsx': ['pdf'], 'xls': ['pdf'], 'ods': ['pdf'],
@@ -134,6 +140,7 @@ export const CONVERSION_MATRIX: Record = {
'md': ['pdf'],
'txt': ['pdf'], 'rtf': ['pdf'],
'eml': ['pdf'],
+ 'cbr': ['pdf'],
'epub': ['pdf'], 'mobi': ['pdf'], 'azw3': ['pdf'], 'fb2': ['pdf']
};
@@ -149,6 +156,7 @@ export const EXTENSION_TO_ENDPOINT: Record> = {
'txt': 'pdf-to-text', 'rtf': 'pdf-to-text', 'md': 'pdf-to-markdown',
'html': 'pdf-to-html', 'xml': 'pdf-to-xml',
'pdfa': 'pdf-to-pdfa',
+ 'cbr': 'pdf-to-cbr',
'cbz': 'pdf-to-cbz'
},
'cbz': { 'pdf': 'cbz-to-pdf' },
@@ -161,6 +169,7 @@ export const EXTENSION_TO_ENDPOINT: Record> = {
'zip': { 'pdf': 'html-to-pdf' },
'md': { 'pdf': 'markdown-to-pdf' },
'txt': { 'pdf': 'file-to-pdf' }, 'rtf': { 'pdf': 'file-to-pdf' },
+ 'cbr': { 'pdf': 'cbr-to-pdf' },
'eml': { 'pdf': 'eml-to-pdf' },
'epub': { 'pdf': 'ebook-to-pdf' }, 'mobi': { 'pdf': 'ebook-to-pdf' }, 'azw3': { 'pdf': 'ebook-to-pdf' }, 'fb2': { 'pdf': 'ebook-to-pdf' }
};
diff --git a/frontend/src/core/constants/convertSupportedFornats.ts b/frontend/src/core/constants/convertSupportedFornats.ts
index afd1f4384..49adf35a6 100644
--- a/frontend/src/core/constants/convertSupportedFornats.ts
+++ b/frontend/src/core/constants/convertSupportedFornats.ts
@@ -15,7 +15,7 @@ export const CONVERT_SUPPORTED_FORMATS = [
// Ebook formats
'epub', 'mobi', 'azw3', 'fb2',
// Archive formats
- 'zip', 'cbz',
+ 'zip', 'cbr', 'cbz',
// Other
'dbf', 'fods', 'vsd', 'vor', 'vor3', 'vor4', 'uop', 'pct', 'ps', 'pdf',
];
diff --git a/frontend/src/core/hooks/tools/convert/useConvertOperation.ts b/frontend/src/core/hooks/tools/convert/useConvertOperation.ts
index d5867422f..8fae6cbcf 100644
--- a/frontend/src/core/hooks/tools/convert/useConvertOperation.ts
+++ b/frontend/src/core/hooks/tools/convert/useConvertOperation.ts
@@ -21,6 +21,8 @@ export const shouldProcessFilesSeparately = (
(parameters.fromExtension === 'pdf' && parameters.toExtension === 'pdfa') ||
// PDF to text-like formats should be one output per input
(parameters.fromExtension === 'pdf' && ['txt', 'rtf', 'csv'].includes(parameters.toExtension)) ||
+ // PDF to CBR conversions (each PDF should generate its own archive)
+ (parameters.fromExtension === 'pdf' && parameters.toExtension === 'cbr') ||
// PDF to office format conversions (each PDF should generate its own office file)
(parameters.fromExtension === 'pdf' && isOfficeFormat(parameters.toExtension)) ||
// Office files to PDF conversions (each file should be processed separately via LibreOffice)
@@ -40,12 +42,12 @@ export const shouldProcessFilesSeparately = (
// Static function that can be used by both the hook and automation executor
export const buildConvertFormData = (parameters: ConvertParameters, selectedFiles: File[]): FormData => {
const formData = new FormData();
+ const { fromExtension, toExtension, imageOptions, htmlOptions, emailOptions, pdfaOptions, cbrOptions, pdfToCbrOptions, cbzOptions, cbzOutputOptions, ebookOptions } = parameters;
selectedFiles.forEach(file => {
formData.append("fileInput", file);
});
- const { fromExtension, toExtension, imageOptions, htmlOptions, emailOptions, pdfaOptions, cbzOptions, cbzOutputOptions, ebookOptions } = parameters;
if (isImageFormat(toExtension)) {
formData.append("imageFormat", toExtension);
@@ -73,6 +75,10 @@ export const buildConvertFormData = (parameters: ConvertParameters, selectedFile
formData.append("outputFormat", pdfaOptions.outputFormat);
} else if (fromExtension === 'pdf' && toExtension === 'csv') {
formData.append("pageNumbers", "all");
+ } else if (fromExtension === 'cbr' && toExtension === 'pdf') {
+ formData.append("optimizeForEbook", cbrOptions.optimizeForEbook.toString());
+ } else if (fromExtension === 'pdf' && toExtension === 'cbr') {
+ formData.append("dpi", pdfToCbrOptions.dpi.toString());
} else if (fromExtension === 'cbz' && toExtension === 'pdf') {
formData.append("optimizeForEbook", (cbzOptions?.optimizeForEbook ?? false).toString());
} else if (fromExtension === 'pdf' && toExtension === 'cbz') {
diff --git a/frontend/src/core/hooks/tools/convert/useConvertParameters.ts b/frontend/src/core/hooks/tools/convert/useConvertParameters.ts
index ce2ae0fd7..e5cd6d6c6 100644
--- a/frontend/src/core/hooks/tools/convert/useConvertParameters.ts
+++ b/frontend/src/core/hooks/tools/convert/useConvertParameters.ts
@@ -36,6 +36,12 @@ export interface ConvertParameters extends BaseParameters {
pdfaOptions: {
outputFormat: string;
};
+ cbrOptions: {
+ optimizeForEbook: boolean;
+ };
+ pdfToCbrOptions: {
+ dpi: number;
+ };
cbzOptions: {
optimizeForEbook: boolean;
};
@@ -81,6 +87,12 @@ export const defaultParameters: ConvertParameters = {
pdfaOptions: {
outputFormat: 'pdfa-1',
},
+ cbrOptions: {
+ optimizeForEbook: false,
+ },
+ pdfToCbrOptions: {
+ dpi: 150,
+ },
cbzOptions: {
optimizeForEbook: false,
},
diff --git a/frontend/src/core/tests/convert/ConvertIntegration.test.tsx b/frontend/src/core/tests/convert/ConvertIntegration.test.tsx
index bb2f0bcf1..73e776c32 100644
--- a/frontend/src/core/tests/convert/ConvertIntegration.test.tsx
+++ b/frontend/src/core/tests/convert/ConvertIntegration.test.tsx
@@ -152,6 +152,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -225,6 +231,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -276,6 +288,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -336,6 +354,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -400,6 +424,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -462,6 +492,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -520,6 +556,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -575,6 +617,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -632,6 +680,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -686,6 +740,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -746,6 +806,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
@@ -805,6 +871,12 @@ describe('Convert Tool Integration Tests', () => {
pdfaOptions: {
outputFormat: ''
},
+ cbrOptions: {
+ optimizeForEbook: false
+ },
+ pdfToCbrOptions: {
+ dpi: 150
+ },
cbzOptions: {
optimizeForEbook: false
},
diff --git a/frontend/src/core/utils/urlMapping.ts b/frontend/src/core/utils/urlMapping.ts
index 9de3d0f5c..f7bb0d666 100644
--- a/frontend/src/core/utils/urlMapping.ts
+++ b/frontend/src/core/utils/urlMapping.ts
@@ -28,6 +28,8 @@ export const URL_TO_TOOL_MAP: Record = {
'/pdf-to-pdfa': 'convert',
'/pdf-to-word': 'convert',
'/pdf-to-xml': 'convert',
+ '/cbr-to-pdf': 'convert',
+ '/pdf-to-cbr': 'convert',
'/cbz-to-pdf': 'convert',
'/pdf-to-cbz': 'convert',