mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-11-16 01:21:16 +01:00
feat(convert): add support for CBR to PDF and PDF to CBR conversions
- Introduced `ConvertFromCbrSettings` and `ConvertToCbrSettings` components for handling conversion-specific settings. - Updated `ConvertSettings` to include CBR-related configurations. - Enhanced `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. Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
This commit is contained in:
parent
4c0c9b28ef
commit
2122b1a323
@ -1079,7 +1079,11 @@
|
||||
"markdown": "Markdown",
|
||||
"textRtf": "Text/RTF",
|
||||
"grayscale": "Greyscale",
|
||||
"errorConversion": "An error occurred while converting the file."
|
||||
"errorConversion": "An error occurred while converting the file.",
|
||||
"cbrOptions": "CBR to PDF Options",
|
||||
"optimizeForEbook": "Optimize PDF for ebook readers (uses Ghostscript)",
|
||||
"cbrOutputOptions": "PDF to CBR Options",
|
||||
"cbrDpi": "DPI for image rendering"
|
||||
},
|
||||
"imageToPdf": {
|
||||
"tags": "conversion,img,jpg,picture,photo"
|
||||
|
||||
@ -2021,6 +2021,10 @@
|
||||
"outputFormat": "Output Format",
|
||||
"pdfaNote": "PDF/A-1b is more compatible, PDF/A-2b supports more features.",
|
||||
"pdfaDigitalSignatureWarning": "The PDF contains a digital signature. This will be removed in the next step.",
|
||||
"cbrOptions": "CBR to PDF Options",
|
||||
"optimizeForEbook": "Optimize PDF for ebook readers (uses Ghostscript)",
|
||||
"cbrOutputOptions": "PDF to CBR Options",
|
||||
"cbrDpi": "DPI for image rendering",
|
||||
"sanitize": {
|
||||
"submit": "Sanitize PDF",
|
||||
"completed": "Sanitization completed successfully",
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
import {Checkbox, Stack, Text } from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ConvertParameters } from "@app/hooks/tools/convert/useConvertParameters";
|
||||
|
||||
interface ConvertFromCbrSettingsProps {
|
||||
parameters: ConvertParameters;
|
||||
onParameterChange: <K extends keyof ConvertParameters>(key: K, value: ConvertParameters[K]) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const ConvertFromCbrSettings = ({
|
||||
parameters,
|
||||
onParameterChange,
|
||||
disabled = false
|
||||
}: ConvertFromCbrSettingsProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Stack gap="sm" data-testid="cbr-options-section">
|
||||
<Text size="sm" fw={500}>{t("convert.cbrOptions", "CBR Options")}:</Text>
|
||||
|
||||
<Checkbox
|
||||
label={t('convert.optimizeForEbook', 'Optimize PDF for ebook readers (uses Ghostscript)')}
|
||||
checked={parameters.cbrOptions.optimizeForEbook}
|
||||
onChange={(event) => onParameterChange('cbrOptions', {
|
||||
...parameters.cbrOptions,
|
||||
optimizeForEbook: event.currentTarget.checked
|
||||
})}
|
||||
disabled={disabled}
|
||||
data-testid="optimize-ebook-checkbox"
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConvertFromCbrSettings;
|
||||
@ -14,6 +14,8 @@ import ConvertFromImageSettings from "@app/components/tools/convert/ConvertFromI
|
||||
import ConvertFromWebSettings from "@app/components/tools/convert/ConvertFromWebSettings";
|
||||
import ConvertFromEmailSettings from "@app/components/tools/convert/ConvertFromEmailSettings";
|
||||
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 { ConvertParameters } from "@app/hooks/tools/convert/useConvertParameters";
|
||||
import {
|
||||
FROM_FORMAT_OPTIONS,
|
||||
@ -118,6 +120,12 @@ const ConvertSettings = ({
|
||||
onParameterChange('pdfaOptions', {
|
||||
outputFormat: 'pdfa-1',
|
||||
});
|
||||
onParameterChange('cbrOptions', {
|
||||
optimizeForEbook: false,
|
||||
});
|
||||
onParameterChange('pdfToCbrOptions', {
|
||||
dpi: 150,
|
||||
});
|
||||
onParameterChange('isSmartDetection', false);
|
||||
onParameterChange('smartDetectionType', 'none');
|
||||
};
|
||||
@ -180,6 +188,12 @@ const ConvertSettings = ({
|
||||
onParameterChange('pdfaOptions', {
|
||||
outputFormat: 'pdfa-1',
|
||||
});
|
||||
onParameterChange('cbrOptions', {
|
||||
optimizeForEbook: false,
|
||||
});
|
||||
onParameterChange('pdfToCbrOptions', {
|
||||
dpi: 150,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -306,6 +320,30 @@ const ConvertSettings = ({
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* CBR to PDF options */}
|
||||
{parameters.fromExtension === 'cbr' && parameters.toExtension === 'pdf' && (
|
||||
<>
|
||||
<Divider />
|
||||
<ConvertFromCbrSettings
|
||||
parameters={parameters}
|
||||
onParameterChange={onParameterChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* PDF to CBR options */}
|
||||
{parameters.fromExtension === 'pdf' && parameters.toExtension === 'cbr' && (
|
||||
<>
|
||||
<Divider />
|
||||
<ConvertToCbrSettings
|
||||
parameters={parameters}
|
||||
onParameterChange={onParameterChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@ -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: <K extends keyof ConvertParameters>(key: K, value: ConvertParameters[K]) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const ConvertToCbrSettings = ({
|
||||
parameters,
|
||||
onParameterChange,
|
||||
disabled = false
|
||||
}: ConvertToCbrSettingsProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Stack gap="sm" data-testid="cbr-output-options-section">
|
||||
<Text size="sm" fw={500}>{t("convert.cbrOutputOptions", "PDF to CBR Options")}:</Text>
|
||||
|
||||
<NumberInput
|
||||
data-testid="cbr-dpi-input"
|
||||
label={t("convert.cbrDpi", "DPI for image rendering")}
|
||||
value={parameters.pdfToCbrOptions.dpi}
|
||||
onChange={(value) => onParameterChange('pdfToCbrOptions', {
|
||||
...parameters.pdfToCbrOptions,
|
||||
dpi: typeof value === 'number' ? value : 150
|
||||
})}
|
||||
min={72}
|
||||
max={600}
|
||||
step={50}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConvertToCbrSettings;
|
||||
@ -31,7 +31,9 @@ export const CONVERSION_ENDPOINTS = {
|
||||
'pdf-pdfa': '/api/v1/convert/pdf/pdfa',
|
||||
'html-pdf': '/api/v1/convert/html/pdf',
|
||||
'markdown-pdf': '/api/v1/convert/markdown/pdf',
|
||||
'eml-pdf': '/api/v1/convert/eml/pdf'
|
||||
'eml-pdf': '/api/v1/convert/eml/pdf',
|
||||
'cbr-pdf': '/api/v1/convert/cbr/pdf',
|
||||
'pdf-cbr': '/api/v1/convert/pdf/cbr'
|
||||
} as const;
|
||||
|
||||
export const ENDPOINT_NAMES = {
|
||||
@ -48,7 +50,9 @@ export const ENDPOINT_NAMES = {
|
||||
'pdf-pdfa': 'pdf-to-pdfa',
|
||||
'html-pdf': 'html-to-pdf',
|
||||
'markdown-pdf': 'markdown-to-pdf',
|
||||
'eml-pdf': 'eml-to-pdf'
|
||||
'eml-pdf': 'eml-to-pdf',
|
||||
'cbr-pdf': 'cbr-to-pdf',
|
||||
'pdf-cbr': 'pdf-to-cbr'
|
||||
} as const;
|
||||
|
||||
|
||||
@ -80,6 +84,7 @@ export const FROM_FORMAT_OPTIONS = [
|
||||
{ value: 'txt', label: 'TXT', group: 'Text' },
|
||||
{ value: 'rtf', label: 'RTF', group: 'Text' },
|
||||
{ value: 'eml', label: 'EML', group: 'Email' },
|
||||
{ value: 'cbr', label: 'CBR', group: 'Archive' },
|
||||
];
|
||||
|
||||
export const TO_FORMAT_OPTIONS = [
|
||||
@ -101,13 +106,14 @@ export const TO_FORMAT_OPTIONS = [
|
||||
{ value: 'webp', label: 'WEBP', group: 'Image' },
|
||||
{ value: 'html', label: 'HTML', group: 'Web' },
|
||||
{ value: 'xml', label: 'XML', group: 'Web' },
|
||||
{ value: 'cbr', label: 'CBR', group: 'Archive' },
|
||||
];
|
||||
|
||||
// Conversion matrix - what each source format can convert to
|
||||
export const CONVERSION_MATRIX: Record<string, string[]> = {
|
||||
'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'],
|
||||
'pdf': ['png', 'jpg', 'gif', 'tiff', 'bmp', 'webp', 'docx', 'odt', 'pptx', 'odp', 'csv', 'txt', 'rtf', 'md', 'html', 'xml', 'pdfa', 'cbr'],
|
||||
'docx': ['pdf'], 'doc': ['pdf'], 'odt': ['pdf'],
|
||||
'xlsx': ['pdf'], 'xls': ['pdf'], 'ods': ['pdf'],
|
||||
'pptx': ['pdf'], 'ppt': ['pdf'], 'odp': ['pdf'],
|
||||
@ -116,7 +122,8 @@ export const CONVERSION_MATRIX: Record<string, string[]> = {
|
||||
'zip': ['pdf'],
|
||||
'md': ['pdf'],
|
||||
'txt': ['pdf'], 'rtf': ['pdf'],
|
||||
'eml': ['pdf']
|
||||
'eml': ['pdf'],
|
||||
'cbr': ['pdf']
|
||||
};
|
||||
|
||||
// Map extensions to endpoint keys
|
||||
@ -130,7 +137,8 @@ export const EXTENSION_TO_ENDPOINT: Record<string, Record<string, string>> = {
|
||||
'csv': 'pdf-to-csv',
|
||||
'txt': 'pdf-to-text', 'rtf': 'pdf-to-text', 'md': 'pdf-to-markdown',
|
||||
'html': 'pdf-to-html', 'xml': 'pdf-to-xml',
|
||||
'pdfa': 'pdf-to-pdfa'
|
||||
'pdfa': 'pdf-to-pdfa',
|
||||
'cbr': 'pdf-to-cbr'
|
||||
},
|
||||
'docx': { 'pdf': 'file-to-pdf' }, 'doc': { 'pdf': 'file-to-pdf' }, 'odt': { 'pdf': 'file-to-pdf' },
|
||||
'xlsx': { 'pdf': 'file-to-pdf' }, 'xls': { 'pdf': 'file-to-pdf' }, 'ods': { 'pdf': 'file-to-pdf' },
|
||||
@ -141,7 +149,8 @@ export const EXTENSION_TO_ENDPOINT: Record<string, Record<string, string>> = {
|
||||
'zip': { 'pdf': 'html-to-pdf' },
|
||||
'md': { 'pdf': 'markdown-to-pdf' },
|
||||
'txt': { 'pdf': 'file-to-pdf' }, 'rtf': { 'pdf': 'file-to-pdf' },
|
||||
'eml': { 'pdf': 'eml-to-pdf' }
|
||||
'eml': { 'pdf': 'eml-to-pdf' },
|
||||
'cbr': { 'pdf': 'cbr-to-pdf' }
|
||||
};
|
||||
|
||||
export type ColorType = typeof COLOR_TYPES[keyof typeof COLOR_TYPES];
|
||||
|
||||
@ -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') ||
|
||||
// Web files to PDF conversions (each web file should generate its own PDF)
|
||||
((isWebFormat(parameters.fromExtension) || parameters.fromExtension === 'web') &&
|
||||
parameters.toExtension === 'pdf') ||
|
||||
@ -39,7 +41,7 @@ export const buildConvertFormData = (parameters: ConvertParameters, selectedFile
|
||||
formData.append("fileInput", file);
|
||||
});
|
||||
|
||||
const { fromExtension, toExtension, imageOptions, htmlOptions, emailOptions, pdfaOptions } = parameters;
|
||||
const { fromExtension, toExtension, imageOptions, htmlOptions, emailOptions, pdfaOptions, cbrOptions, pdfToCbrOptions } = parameters;
|
||||
|
||||
if (isImageFormat(toExtension)) {
|
||||
formData.append("imageFormat", toExtension);
|
||||
@ -67,6 +69,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());
|
||||
}
|
||||
|
||||
return formData;
|
||||
|
||||
@ -36,6 +36,12 @@ export interface ConvertParameters extends BaseParameters {
|
||||
pdfaOptions: {
|
||||
outputFormat: string;
|
||||
};
|
||||
cbrOptions: {
|
||||
optimizeForEbook: boolean;
|
||||
};
|
||||
pdfToCbrOptions: {
|
||||
dpi: number;
|
||||
};
|
||||
isSmartDetection: boolean;
|
||||
smartDetectionType: 'mixed' | 'images' | 'web' | 'none';
|
||||
}
|
||||
@ -69,6 +75,12 @@ export const defaultParameters: ConvertParameters = {
|
||||
pdfaOptions: {
|
||||
outputFormat: 'pdfa-1',
|
||||
},
|
||||
cbrOptions: {
|
||||
optimizeForEbook: false,
|
||||
},
|
||||
pdfToCbrOptions: {
|
||||
dpi: 150,
|
||||
},
|
||||
isSmartDetection: false,
|
||||
smartDetectionType: 'none',
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user