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 e9d0085350..f9e13f3c1e 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 32ad108407..953bd018f9 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 94da35af55..87b458e104 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 0000000000..8f1a809469
--- /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 c31928112b..127fbb13c7 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 0000000000..db85eda774
--- /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 80e2059675..0ffe5783f9 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 afd1f43847..49adf35a6a 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 d5867422f7..8fae6cbcfe 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 ce2ae0fd75..e5cd6d6c65 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 bb2f0bcf11..73e776c326 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 9de3d0f5c8..f7bb0d666b 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',