mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-04-16 23:08:38 +02:00
feat: split pdf into small chunks by pdfbox (#5718)
Co-authored-by: Ubuntu <ubuntu@vps-1aebde64.vps.ovh.ca> Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
This commit is contained in:
@@ -160,6 +160,55 @@ const SplitSettings = ({
|
||||
</Stack>
|
||||
);
|
||||
|
||||
const renderByPosterForm = () => (
|
||||
<Stack gap="sm">
|
||||
<Select
|
||||
label={t("split.poster.pageSize.label", "Target Page Size")}
|
||||
description={t("split.poster.pageSize.description", "Size of output pages for printing")}
|
||||
value={parameters.pageSize || 'A4'}
|
||||
onChange={(value) => onParameterChange('pageSize', value || 'A4')}
|
||||
data={[
|
||||
{ value: 'A4', label: 'A4 (210 × 297 mm)' },
|
||||
{ value: 'Letter', label: 'Letter (8.5 × 11 in)' },
|
||||
{ value: 'A3', label: 'A3 (297 × 420 mm)' },
|
||||
{ value: 'A5', label: 'A5 (148 × 210 mm)' },
|
||||
{ value: 'Legal', label: 'Legal (8.5 × 14 in)' },
|
||||
{ value: 'Tabloid', label: 'Tabloid (11 × 17 in)' },
|
||||
]}
|
||||
disabled={disabled}
|
||||
comboboxProps={{ withinPortal: true, zIndex: Z_INDEX_AUTOMATE_DROPDOWN }}
|
||||
/>
|
||||
<TextInput
|
||||
label={t("split.poster.xFactor.label", "Horizontal Divisions")}
|
||||
description={t("split.poster.xFactor.description", "Number of columns to split each page into")}
|
||||
type="number"
|
||||
min="1"
|
||||
max="10"
|
||||
value={parameters.xFactor || 2}
|
||||
onChange={(e) => onParameterChange('xFactor', e.target.value)}
|
||||
placeholder="2"
|
||||
disabled={disabled}
|
||||
/>
|
||||
<TextInput
|
||||
label={t("split.poster.yFactor.label", "Vertical Divisions")}
|
||||
description={t("split.poster.yFactor.description", "Number of rows to split each page into")}
|
||||
type="number"
|
||||
min="1"
|
||||
max="10"
|
||||
value={parameters.yFactor || 2}
|
||||
onChange={(e) => onParameterChange('yFactor', e.target.value)}
|
||||
placeholder="2"
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Checkbox
|
||||
label={t("split.poster.rightToLeft", "Split right-to-left")}
|
||||
checked={parameters.rightToLeft || false}
|
||||
onChange={(e) => onParameterChange('rightToLeft', e.currentTarget.checked)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
// Don't render anything if no method is selected
|
||||
if (!parameters.method) {
|
||||
return (
|
||||
@@ -181,6 +230,7 @@ const SplitSettings = ({
|
||||
parameters.method === SPLIT_METHODS.BY_DOC_COUNT) && renderSplitValueForm()}
|
||||
{parameters.method === SPLIT_METHODS.BY_CHAPTERS && renderByChaptersForm()}
|
||||
{parameters.method === SPLIT_METHODS.BY_PAGE_DIVIDER && renderByPageDividerForm()}
|
||||
{parameters.method === SPLIT_METHODS.BY_POSTER && renderByPosterForm()}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -127,6 +127,24 @@ export const useSplitSettingsTips = (method: SplitMethod | ''): TooltipContent |
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
[SPLIT_METHODS.BY_POSTER]: {
|
||||
header: {
|
||||
title: t("split.tooltip.byPoster.title", "Split for Poster Print")
|
||||
},
|
||||
tips: [
|
||||
{
|
||||
title: t("split.tooltip.byPoster.title", "Split for Poster Print"),
|
||||
description: t("split.tooltip.byPoster.text", "Split large PDF pages into smaller printable chunks suitable for standard paper sizes. Perfect for creating poster prints from oversized pages."),
|
||||
bullets: [
|
||||
t("split.tooltip.byPoster.bullet1", "Target Page Size: Choose output paper size (A4, Letter, etc.)"),
|
||||
t("split.tooltip.byPoster.bullet2", "Horizontal/Vertical Divisions: Grid size for splitting"),
|
||||
t("split.tooltip.byPoster.bullet3", "Right-to-Left: Reverse column order for RTL layouts"),
|
||||
t("split.tooltip.byPoster.bullet4", "Print and assemble the pieces to create your poster")
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ export const SPLIT_METHODS = {
|
||||
BY_PAGE_COUNT: 'byPageCount',
|
||||
BY_DOC_COUNT: 'byDocCount',
|
||||
BY_CHAPTERS: 'byChapters',
|
||||
BY_PAGE_DIVIDER: 'byPageDivider'
|
||||
BY_PAGE_DIVIDER: 'byPageDivider',
|
||||
BY_POSTER: 'byPoster'
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -16,7 +17,8 @@ export const ENDPOINTS = {
|
||||
[SPLIT_METHODS.BY_PAGE_COUNT]: 'split-by-size-or-count',
|
||||
[SPLIT_METHODS.BY_DOC_COUNT]: 'split-by-size-or-count',
|
||||
[SPLIT_METHODS.BY_CHAPTERS]: 'split-pdf-by-chapters',
|
||||
[SPLIT_METHODS.BY_PAGE_DIVIDER]: 'auto-split-pdf'
|
||||
[SPLIT_METHODS.BY_PAGE_DIVIDER]: 'auto-split-pdf',
|
||||
[SPLIT_METHODS.BY_POSTER]: 'split-for-poster-print'
|
||||
} as const;
|
||||
|
||||
export type SplitMethod = typeof SPLIT_METHODS[keyof typeof SPLIT_METHODS];
|
||||
@@ -72,6 +74,12 @@ export const METHOD_OPTIONS: MethodOption[] = [
|
||||
prefixKey: "split.methods.prefix.splitBy",
|
||||
nameKey: "split.methods.byPageDivider.name",
|
||||
tooltipKey: "split.methods.byPageDivider.tooltip"
|
||||
},
|
||||
{
|
||||
value: SPLIT_METHODS.BY_POSTER,
|
||||
prefixKey: "split.methods.prefix.splitInto",
|
||||
nameKey: "split.methods.byPoster.name",
|
||||
tooltipKey: "split.methods.byPoster.tooltip"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -45,6 +45,12 @@ export const buildSplitFormData = (parameters: SplitParameters, file: File): For
|
||||
case SPLIT_METHODS.BY_PAGE_DIVIDER:
|
||||
formData.append("duplexMode", (parameters.duplexMode ?? false).toString());
|
||||
break;
|
||||
case SPLIT_METHODS.BY_POSTER:
|
||||
formData.append("pageSize", parameters.pageSize || 'A4');
|
||||
formData.append("xFactor", parameters.xFactor || '2');
|
||||
formData.append("yFactor", parameters.yFactor || '2');
|
||||
formData.append("rightToLeft", (parameters.rightToLeft ?? false).toString());
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown split method: ${parameters.method}`);
|
||||
}
|
||||
@@ -66,6 +72,8 @@ export const getSplitEndpoint = (parameters: SplitParameters): string => {
|
||||
return "/api/v1/general/split-pdf-by-chapters";
|
||||
case SPLIT_METHODS.BY_PAGE_DIVIDER:
|
||||
return "/api/v1/misc/auto-split-pdf";
|
||||
case SPLIT_METHODS.BY_POSTER:
|
||||
return "/api/v1/general/split-for-poster-print";
|
||||
default:
|
||||
throw new Error(`Unknown split method: ${parameters.method}`);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ export interface SplitParameters extends BaseParameters {
|
||||
duplexMode: boolean;
|
||||
splitMode?: string;
|
||||
customPages?: string;
|
||||
pageSize?: string;
|
||||
xFactor?: string;
|
||||
yFactor?: string;
|
||||
rightToLeft?: boolean;
|
||||
}
|
||||
|
||||
export type SplitParametersHook = BaseParametersHook<SplitParameters>;
|
||||
@@ -32,6 +36,10 @@ export const defaultParameters: SplitParameters = {
|
||||
duplexMode: false,
|
||||
splitMode: 'SPLIT_ALL',
|
||||
customPages: '',
|
||||
pageSize: 'A4',
|
||||
xFactor: '2',
|
||||
yFactor: '2',
|
||||
rightToLeft: false,
|
||||
};
|
||||
|
||||
export const useSplitParameters = (): SplitParametersHook => {
|
||||
@@ -61,6 +69,8 @@ export const useSplitParameters = (): SplitParametersHook => {
|
||||
return params.bookmarkLevel !== "";
|
||||
case SPLIT_METHODS.BY_PAGE_DIVIDER:
|
||||
return true; // No required parameters
|
||||
case SPLIT_METHODS.BY_POSTER:
|
||||
return params.pageSize !== "" && params.xFactor !== "" && params.yFactor !== "";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ const extractKeys = (file: string): FoundKey[] => {
|
||||
};
|
||||
|
||||
describe('Missing translation coverage', () => {
|
||||
test('fails if any en-GB translation key used in source is missing', () => {
|
||||
test('fails if any en-GB translation key used in source is missing', { timeout: 10000 }, () => {
|
||||
expect(fs.existsSync(EN_GB_FILE)).toBe(true);
|
||||
|
||||
const localeContent = fs.readFileSync(EN_GB_FILE, 'utf8');
|
||||
|
||||
Reference in New Issue
Block a user