mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 22:29:24 +00:00
Initial commit of Merge UI
This commit is contained in:
parent
23d86deae7
commit
86831928c7
59
frontend/src/components/tools/merge/MergeSettings.tsx
Normal file
59
frontend/src/components/tools/merge/MergeSettings.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Stack, Select, Checkbox, Text } from '@mantine/core';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { MergeParameters } from '../../../hooks/tools/merge/useMergeParameters';
|
||||||
|
|
||||||
|
interface MergeSettingsProps {
|
||||||
|
parameters: MergeParameters;
|
||||||
|
onParameterChange: <K extends keyof MergeParameters>(key: K, value: MergeParameters[K]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MergeSettings: React.FC<MergeSettingsProps> = ({
|
||||||
|
parameters,
|
||||||
|
onParameterChange,
|
||||||
|
disabled = false,
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const mergeOrderOptions = [
|
||||||
|
{ value: 'orderProvided', label: t('merge.orderBy.orderProvided', 'Dragging Files') },
|
||||||
|
{ value: 'byFileName', label: t('merge.orderBy.byFileName', 'By File Name') },
|
||||||
|
{ value: 'byDateModified', label: t('merge.orderBy.byDateModified', 'By Date Modified') },
|
||||||
|
{ value: 'byDateCreated', label: t('merge.orderBy.byDateCreated', 'By Date Created') },
|
||||||
|
{ value: 'byPDFTitle', label: t('merge.orderBy.byPDFTitle', 'By PDF Title') },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="md">
|
||||||
|
<div>
|
||||||
|
<Text size="sm" fw={500} mb="xs">
|
||||||
|
{t('merge.orderBy.title', 'Merge Order')}
|
||||||
|
</Text>
|
||||||
|
<Select
|
||||||
|
data={mergeOrderOptions}
|
||||||
|
value={parameters.mergeOrder}
|
||||||
|
onChange={(value) => onParameterChange('mergeOrder', value as MergeParameters['mergeOrder'])}
|
||||||
|
disabled={disabled}
|
||||||
|
placeholder={t('merge.orderBy.placeholder', 'Select merge order')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Checkbox
|
||||||
|
label={t('merge.removeDigitalSignature', 'Remove digital signature in the merged file?')}
|
||||||
|
checked={parameters.removeDigitalSignature}
|
||||||
|
onChange={(event) => onParameterChange('removeDigitalSignature', event.currentTarget.checked)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Checkbox
|
||||||
|
label={t('merge.generateTableOfContents', 'Generate table of contents in the merged file?')}
|
||||||
|
checked={parameters.generateTableOfContents}
|
||||||
|
onChange={(event) => onParameterChange('generateTableOfContents', event.currentTarget.checked)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MergeSettings;
|
35
frontend/src/hooks/tools/merge/useMergeOperation.ts
Normal file
35
frontend/src/hooks/tools/merge/useMergeOperation.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useToolOperation, ResponseHandler } from '../shared/useToolOperation';
|
||||||
|
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||||
|
import { MergeParameters } from './useMergeParameters';
|
||||||
|
|
||||||
|
const buildFormData = (parameters: MergeParameters, files: File[]): FormData => {
|
||||||
|
const formData = new FormData();
|
||||||
|
|
||||||
|
files.forEach((file) => {
|
||||||
|
formData.append("fileInput", file);
|
||||||
|
});
|
||||||
|
formData.append("sortType", parameters.mergeOrder);
|
||||||
|
formData.append("removeCertSign", parameters.removeDigitalSignature.toString());
|
||||||
|
formData.append("generateToc", parameters.generateTableOfContents.toString());
|
||||||
|
|
||||||
|
return formData;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mergeResponseHandler: ResponseHandler = (blob: Blob, originalFiles: File[]): File[] => {
|
||||||
|
return [new File([blob], 'merged.pdf', { type: 'application/pdf' })];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMergeOperation = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return useToolOperation<MergeParameters>({
|
||||||
|
operationType: 'merge',
|
||||||
|
endpoint: '/api/v1/general/merge-pdfs',
|
||||||
|
buildFormData,
|
||||||
|
filePrefix: 'merged_',
|
||||||
|
multiFileEndpoint: true, // Single API call with all files
|
||||||
|
responseHandler: mergeResponseHandler, // Handle single PDF response
|
||||||
|
getErrorMessage: createStandardErrorHandler(t('merge.error.failed', 'An error occurred while merging the PDFs.'))
|
||||||
|
});
|
||||||
|
};
|
39
frontend/src/hooks/tools/merge/useMergeParameters.ts
Normal file
39
frontend/src/hooks/tools/merge/useMergeParameters.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { useState, useCallback } from 'react';
|
||||||
|
|
||||||
|
export interface MergeParameters {
|
||||||
|
mergeOrder: 'orderProvided' | 'byFileName' | 'byDateModified' | 'byDateCreated' | 'byPDFTitle';
|
||||||
|
removeDigitalSignature: boolean;
|
||||||
|
generateTableOfContents: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultMergeParameters: MergeParameters = {
|
||||||
|
mergeOrder: 'orderProvided',
|
||||||
|
removeDigitalSignature: false,
|
||||||
|
generateTableOfContents: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMergeParameters = () => {
|
||||||
|
const [parameters, setParameters] = useState<MergeParameters>(defaultMergeParameters);
|
||||||
|
|
||||||
|
const updateParameter = useCallback(<K extends keyof MergeParameters>(
|
||||||
|
key: K,
|
||||||
|
value: MergeParameters[K]
|
||||||
|
) => {
|
||||||
|
setParameters(prev => ({ ...prev, [key]: value }));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const validateParameters = useCallback((): boolean => {
|
||||||
|
return true; // Merge has no required parameters
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const resetParameters = useCallback(() => {
|
||||||
|
setParameters(defaultMergeParameters);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
parameters,
|
||||||
|
updateParameter,
|
||||||
|
validateParameters,
|
||||||
|
resetParameters,
|
||||||
|
};
|
||||||
|
};
|
@ -2,6 +2,7 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useFlatToolRegistry } from "../data/useTranslatedToolRegistry";
|
import { useFlatToolRegistry } from "../data/useTranslatedToolRegistry";
|
||||||
import { getAllEndpoints, type ToolRegistryEntry } from "../data/toolsTaxonomy";
|
import { getAllEndpoints, type ToolRegistryEntry } from "../data/toolsTaxonomy";
|
||||||
|
import MergeIcon from "@mui/icons-material/Merge";
|
||||||
import { useMultipleEndpointsEnabled } from "./useEndpointConfig";
|
import { useMultipleEndpointsEnabled } from "./useEndpointConfig";
|
||||||
|
|
||||||
interface ToolManagementResult {
|
interface ToolManagementResult {
|
||||||
|
95
frontend/src/tools/Merge.tsx
Normal file
95
frontend/src/tools/Merge.tsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
||||||
|
import { useFileContext } from "../contexts/FileContext";
|
||||||
|
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
||||||
|
|
||||||
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
|
import MergeSettings from "../components/tools/merge/MergeSettings";
|
||||||
|
|
||||||
|
import { useMergeParameters } from "../hooks/tools/merge/useMergeParameters";
|
||||||
|
import { useMergeOperation } from "../hooks/tools/merge/useMergeOperation";
|
||||||
|
import { BaseToolProps } from "../types/tool";
|
||||||
|
|
||||||
|
const Merge = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { setCurrentMode } = useFileContext();
|
||||||
|
const { selectedFiles } = useToolFileSelection();
|
||||||
|
|
||||||
|
const mergeParams = useMergeParameters();
|
||||||
|
const mergeOperation = useMergeOperation();
|
||||||
|
|
||||||
|
// Endpoint validation
|
||||||
|
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled("merge-pdfs");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
mergeOperation.resetResults();
|
||||||
|
onPreviewFile?.(null);
|
||||||
|
}, [mergeParams.parameters]);
|
||||||
|
|
||||||
|
const handleMerge = async () => {
|
||||||
|
try {
|
||||||
|
await mergeOperation.executeOperation(mergeParams.parameters, selectedFiles);
|
||||||
|
if (mergeOperation.files && onComplete) {
|
||||||
|
onComplete(mergeOperation.files);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (onError) {
|
||||||
|
onError(error instanceof Error ? error.message : "Merge operation failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleThumbnailClick = (file: File) => {
|
||||||
|
onPreviewFile?.(file);
|
||||||
|
sessionStorage.setItem("previousMode", "merge");
|
||||||
|
setCurrentMode("viewer");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSettingsReset = () => {
|
||||||
|
mergeOperation.resetResults();
|
||||||
|
onPreviewFile?.(null);
|
||||||
|
setCurrentMode("merge");
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasFiles = selectedFiles.length > 1; // Merge requires at least 2 files
|
||||||
|
const hasResults = mergeOperation.files.length > 0 || mergeOperation.downloadUrl !== null;
|
||||||
|
const settingsCollapsed = !hasFiles || hasResults;
|
||||||
|
|
||||||
|
return createToolFlow({
|
||||||
|
files: {
|
||||||
|
selectedFiles,
|
||||||
|
isCollapsed: hasFiles && !hasResults,
|
||||||
|
placeholder: "Select multiple PDF files to merge",
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
title: "Settings",
|
||||||
|
isCollapsed: settingsCollapsed,
|
||||||
|
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
||||||
|
content: (
|
||||||
|
<MergeSettings
|
||||||
|
parameters={mergeParams.parameters}
|
||||||
|
onParameterChange={mergeParams.updateParameter}
|
||||||
|
disabled={endpointLoading}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
executeButton: {
|
||||||
|
text: t("merge.submit", "Merge PDFs"),
|
||||||
|
isVisible: !hasResults,
|
||||||
|
loadingText: t("loading"),
|
||||||
|
onClick: handleMerge,
|
||||||
|
disabled: !mergeParams.validateParameters() || !hasFiles || !endpointEnabled,
|
||||||
|
},
|
||||||
|
review: {
|
||||||
|
isVisible: hasResults,
|
||||||
|
operation: mergeOperation,
|
||||||
|
title: t("merge.title", "Merge Results"),
|
||||||
|
onFileClick: handleThumbnailClick,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Merge;
|
74
testing/test_pdf_1.pdf
Normal file
74
testing/test_pdf_1.pdf
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
%PDF-1.3
|
||||||
|
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 7 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Author (anonymous) /CreationDate (D:20250819094504+01'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20250819094504+01'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||||
|
/Subject (unspecified) /Title (untitled) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 147
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
GarW00abco&4HDcidm(mI,3'DZY:^WQ,7!K+Bf&Mo_p+bJu"KZ.3A(M3%pEBpBe"=Bb3[h-Xt2ROZoe^Q)8NH>;#5qqB`Oee86NZp2V9^`:9`Y'Dq([aoCS4Veh*jH9C%+DV`*GHUK^ngc-TW~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 9
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000073 00000 n
|
||||||
|
0000000114 00000 n
|
||||||
|
0000000221 00000 n
|
||||||
|
0000000333 00000 n
|
||||||
|
0000000526 00000 n
|
||||||
|
0000000594 00000 n
|
||||||
|
0000000890 00000 n
|
||||||
|
0000000949 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<cb35d644a26f0c9be3597a7f8189b123><cb35d644a26f0c9be3597a7f8189b123>]
|
||||||
|
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||||
|
|
||||||
|
/Info 6 0 R
|
||||||
|
/Root 5 0 R
|
||||||
|
/Size 9
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1186
|
||||||
|
%%EOF
|
74
testing/test_pdf_2.pdf
Normal file
74
testing/test_pdf_2.pdf
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
%PDF-1.3
|
||||||
|
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 7 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Author (anonymous) /CreationDate (D:20250819094504+01'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20250819094504+01'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||||
|
/Subject (unspecified) /Title (untitled) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 147
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
GarW00abco&4HDcidm(mI,3'DZY:^WQ,7!K+Bf&Mo_p+bJu"KZ.3A(M3%pEBpBe"=Bb3[h-Xt2ROZoe^Q)8NH>;#5qqB`Oee86NZp3Iif`:9`Y'Dq([aoCS4Veh*jH9C%+DV`*GHUK^ngmo`i~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 9
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000073 00000 n
|
||||||
|
0000000114 00000 n
|
||||||
|
0000000221 00000 n
|
||||||
|
0000000333 00000 n
|
||||||
|
0000000526 00000 n
|
||||||
|
0000000594 00000 n
|
||||||
|
0000000890 00000 n
|
||||||
|
0000000949 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<46f6a3460762da2956d1d3fc19ab996f><46f6a3460762da2956d1d3fc19ab996f>]
|
||||||
|
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||||
|
|
||||||
|
/Info 6 0 R
|
||||||
|
/Root 5 0 R
|
||||||
|
/Size 9
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1186
|
||||||
|
%%EOF
|
74
testing/test_pdf_3.pdf
Normal file
74
testing/test_pdf_3.pdf
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
%PDF-1.3
|
||||||
|
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 7 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Author (anonymous) /CreationDate (D:20250819094504+01'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20250819094504+01'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||||
|
/Subject (unspecified) /Title (untitled) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 147
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
GarW0YmS?5&4HDC`<2TCEOpM_A^cO6ZEVtG&1rQ7k5R.W5uPe>'T[Ma*9KfZqZs*-57""%'<u)dPtNs!.p_7Cem+LKojd:CaF,4$g:S_<`9sPL'Dq([aoCSX;_^WU4Wa'KgNd255,.iQh#\m&~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 9
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000073 00000 n
|
||||||
|
0000000114 00000 n
|
||||||
|
0000000221 00000 n
|
||||||
|
0000000333 00000 n
|
||||||
|
0000000526 00000 n
|
||||||
|
0000000594 00000 n
|
||||||
|
0000000890 00000 n
|
||||||
|
0000000949 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<8c4eba11c30780ded30147f80c0aa46f><8c4eba11c30780ded30147f80c0aa46f>]
|
||||||
|
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||||
|
|
||||||
|
/Info 6 0 R
|
||||||
|
/Root 5 0 R
|
||||||
|
/Size 9
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1186
|
||||||
|
%%EOF
|
74
testing/test_pdf_4.pdf
Normal file
74
testing/test_pdf_4.pdf
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
%PDF-1.3
|
||||||
|
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 7 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Author (anonymous) /CreationDate (D:20250819094504+01'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20250819094504+01'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||||
|
/Subject (unspecified) /Title (untitled) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 147
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
GarW00abco&4HDcidm(mI,3'DZY:^WQ,7!K+Bf&Mo_p+bJu"KZ.3A(M3%pEBpBe"=Bb3[h-Xt2ROZoe^Q)8NH>;#5qqB`Oee86NZp3%Qb`:9`Y'Dq([aoCS4Veh*jH9C%+DV`*GHUK^nh.J$8~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 9
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000073 00000 n
|
||||||
|
0000000114 00000 n
|
||||||
|
0000000221 00000 n
|
||||||
|
0000000333 00000 n
|
||||||
|
0000000526 00000 n
|
||||||
|
0000000594 00000 n
|
||||||
|
0000000890 00000 n
|
||||||
|
0000000949 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<ade40b97468692afaf20f74813f90619><ade40b97468692afaf20f74813f90619>]
|
||||||
|
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||||
|
|
||||||
|
/Info 6 0 R
|
||||||
|
/Root 5 0 R
|
||||||
|
/Size 9
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1186
|
||||||
|
%%EOF
|
Loading…
x
Reference in New Issue
Block a user