[V2] feat(getPdfInfo): add attachment, embedded file, and image info display (#5278)

# Description of Changes

This pull request enhances the display of PDF metadata in the "Other"
and "Per Page" sections by introducing more detailed and user-friendly
rendering of attachments, embedded files, and images. The changes add
new helper functions for rendering these lists and extend the type
definitions to support richer information, improving the clarity and
usefulness of the UI.

**Improvements to PDF metadata rendering:**

* Added `renderAttachmentsList` and `renderEmbeddedFilesList` helper
functions in `OtherSection.tsx` to display detailed information about
attachments and embedded files, including name, description, file size,
MIME type, and dates. These replace the generic list renderer for these
fields.
* Added `renderImagesList` helper function in `PerPageSection.tsx` to
display images with their name, dimensions, and color space, replacing
the generic list renderer for images.

**Type definition enhancements:**

* Extended `PdfEmbeddedFileInfo` and `PdfAttachmentInfo` in
`getPdfInfo.ts` to include additional fields: `FileSize`, `MimeType`,
`CreationDate`, and `ModificationDate` for embedded files, and
`FileSize` for attachments.

<img width="1920" height="998" alt="image"
src="https://github.com/user-attachments/assets/249409c1-4fd5-4599-b8f9-07093034cb55"
/>

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## 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 <bszucs1209@gmail.com>
This commit is contained in:
Balázs Szücs
2025-12-23 00:05:52 +01:00
committed by GitHub
parent d2a4054120
commit 098f2badec
3 changed files with 62 additions and 5 deletions

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Accordion, Stack, Text } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import type { PdfOtherInfo } from '@app/types/getPdfInfo';
import type { PdfOtherInfo, PdfAttachmentInfo, PdfEmbeddedFileInfo } from '@app/types/getPdfInfo';
import SectionBlock from '@app/components/tools/getPdfInfo/shared/SectionBlock';
import ScrollableCodeBlock from '@app/components/tools/getPdfInfo/shared/ScrollableCodeBlock';
import { pdfInfoAccordionStyles } from '@app/components/tools/getPdfInfo/shared/accordionStyles';
@@ -11,6 +11,42 @@ interface OtherSectionProps {
other?: PdfOtherInfo | null;
}
const renderAttachmentsList = (attachments: PdfAttachmentInfo[] | undefined, emptyText: string) => {
if (!attachments || attachments.length === 0) return <Text size="sm" c="dimmed">{emptyText}</Text>;
return (
<Stack gap={4}>
{attachments.map((attachment, idx) => (
<div key={idx} style={{ wordBreak: 'break-word', overflowWrap: 'break-word' }}>
<Text size="sm" c="dimmed">
<strong>{attachment.Name || 'Unnamed attachment'}</strong>
{attachment.Description && ` - ${attachment.Description}`}
{attachment.FileSize != null && ` (${attachment.FileSize} bytes)`}
</Text>
</div>
))}
</Stack>
);
};
const renderEmbeddedFilesList = (embeddedFiles: PdfEmbeddedFileInfo[] | undefined, emptyText: string) => {
if (!embeddedFiles || embeddedFiles.length === 0) return <Text size="sm" c="dimmed">{emptyText}</Text>;
return (
<Stack gap={4}>
{embeddedFiles.map((file, idx) => (
<div key={idx} style={{ wordBreak: 'break-word', overflowWrap: 'break-word' }}>
<Text size="sm" c="dimmed">
<strong>{file.Name || 'Unnamed file'}</strong>
{file.FileSize != null && ` (${file.FileSize} bytes)`}
{file.MimeType && ` - ${file.MimeType}`}
{file.CreationDate && ` - Created: ${file.CreationDate}`}
{file.ModificationDate && ` - Modified: ${file.ModificationDate}`}
</Text>
</div>
))}
</Stack>
);
};
const renderList = (arr: unknown[] | undefined, emptyText: string) => {
if (!arr || arr.length === 0) return <Text size="sm" c="dimmed">{emptyText}</Text>;
return (
@@ -37,11 +73,11 @@ const OtherSection: React.FC<OtherSectionProps> = ({ anchorId, other }) => {
<Stack gap="sm">
<Stack gap={6}>
<Text fw={600} size="sm">{t('getPdfInfo.other.attachments', 'Attachments')}</Text>
{renderList(other?.Attachments, noneDetected)}
{renderAttachmentsList(other?.Attachments, noneDetected)}
</Stack>
<Stack gap={6}>
<Text fw={600} size="sm">{t('getPdfInfo.other.embeddedFiles', 'Embedded Files')}</Text>
{renderList(other?.EmbeddedFiles, noneDetected)}
{renderEmbeddedFilesList(other?.EmbeddedFiles, noneDetected)}
</Stack>
<Stack gap={6}>
<Text fw={600} size="sm">{t('getPdfInfo.other.javaScript', 'JavaScript')}</Text>

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Accordion, Stack, Text } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import type { PdfPerPageInfo, PdfPageInfo, PdfFontInfo } from '@app/types/getPdfInfo';
import type { PdfPerPageInfo, PdfPageInfo, PdfFontInfo, PdfImageInfo } from '@app/types/getPdfInfo';
import SectionBlock from '@app/components/tools/getPdfInfo/shared/SectionBlock';
import KeyValueList from '@app/components/tools/getPdfInfo/shared/KeyValueList';
import { pdfInfoAccordionStyles } from '@app/components/tools/getPdfInfo/shared/accordionStyles';
@@ -11,6 +11,23 @@ interface PerPageSectionProps {
perPage?: PdfPerPageInfo | null;
}
const renderImagesList = (images: PdfImageInfo[] | undefined, emptyText: string) => {
if (!images || images.length === 0) return <Text size="sm" c="dimmed">{emptyText}</Text>;
return (
<Stack gap={4}>
{images.map((image, idx) => (
<div key={idx} style={{ wordBreak: 'break-word', overflowWrap: 'break-word' }}>
<Text size="sm" c="dimmed">
{image.Name ? `${image.Name} ` : 'Image '}
({image.Width}×{image.Height}px
{image.ColorSpace ? `, ${image.ColorSpace}` : ''})
</Text>
</div>
))}
</Stack>
);
};
const renderList = (arr: unknown[] | undefined, emptyText: string) => {
if (!arr || arr.length === 0) return <Text size="sm" c="dimmed">{emptyText}</Text>;
return (
@@ -84,7 +101,7 @@ const PerPageSection: React.FC<PerPageSectionProps> = ({ anchorId, perPage }) =>
)}
<Stack gap={4}>
<Text fw={600} size="sm">{t('getPdfInfo.perPage.images', 'Images')}</Text>
{renderList(pageInfo?.Images, noneDetected)}
{renderImagesList(pageInfo?.Images, noneDetected)}
</Stack>
<Stack gap={4}>
<Text fw={600} size="sm">{t('getPdfInfo.perPage.links', 'Links')}</Text>

View File

@@ -160,12 +160,16 @@ export interface PdfPerPageInfo {
export interface PdfEmbeddedFileInfo {
Name?: string;
FileSize?: number;
MimeType?: string;
CreationDate?: string;
ModificationDate?: string;
}
/** Attachment info */
export interface PdfAttachmentInfo {
Name?: string;
Description?: string;
FileSize?: number;
}
/** JavaScript info */