Feat: Extract Images from PDF Tool

This commit is contained in:
wz
2026-04-16 15:10:24 +08:00
parent 3fc4509642
commit 083fe4f804
3 changed files with 68 additions and 19 deletions
+2 -1
View File
@@ -131,6 +131,7 @@
"extractImagesFromPdf": {
"description": "Extract images from your PDF file.",
"shortDescription": "Extract images from your PDF file.",
"title": "Extract Images from PDF"
"title": "Extract Images from PDF",
"resultTitle": "Extracted Images Here"
}
}
@@ -1,22 +1,35 @@
import { useState, useEffect } from 'react';
import { useState } from 'react';
import ToolFileResult from '@components/result/ToolFileResult';
import ToolContent from '@components/ToolContent';
import { ToolComponentProps } from '@tools/defineTool';
import ToolPdfInput from '@components/input/ToolPdfInput';
import { processPDF } from './service';
import ToolMultiFileResult from '@components/result/ToolMultiFileResult';
import { useTranslation } from 'react-i18next';
export default function PdfToEpub({ title }: ToolComponentProps) {
const { t } = useTranslation('pdf');
const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null);
const [result, setResult] = useState<File[]>([]);
const [zipFile, setZipFile] = useState<File | null>(null);
const [isProcessing, setIsProcessing] = useState<boolean>(false);
const compute = async (options: {}, input: File | null) => {
if (!input) return;
try {
setIsProcessing(true);
setResult(null);
const epub = await processPDF(input);
setResult(epub);
setResult([]);
const returnedImages = await processPDF(input);
console.log('Processed Images are', returnedImages);
// No result
if (!returnedImages) {
setResult([]);
setZipFile(null);
} else {
setResult(returnedImages.extractedImages);
setZipFile(returnedImages.zipFile);
}
} catch (error) {
console.error('Failed to extract images from PDF:', error);
} finally {
@@ -41,13 +54,21 @@ export default function PdfToEpub({ title }: ToolComponentProps) {
}
getGroups={null}
resultComponent={
<ToolFileResult
title={'Extracted Images'}
value={result}
extension={'epub'}
loading={isProcessing}
loadingText={'Extracting Images from PDF File...'}
/>
zipFile ? (
<ToolMultiFileResult
title={t('extractImagesFromPdf.resultTitle')}
value={result}
zipFile={zipFile}
loading={isProcessing}
/>
) : (
<ToolFileResult
title={t('extractImagesFromPdf.resultTitle')}
value={result[0] ?? null}
extension={'png'}
loading={isProcessing}
/>
)
}
toolInfo={{
title: 'How to Extract Images from PDF File?',
@@ -1,13 +1,17 @@
import * as pdfjsLib from 'pdfjs-dist';
import pdfWorker from 'pdfjs-dist/legacy/build/pdf.worker.min.mjs?url';
import { PdfImageObject } from './types';
import JSZip from 'jszip';
// Initialise The PDF JS Worker
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker;
export async function processPDF(input: File) {
export async function processPDF(
input: File
): Promise<{ extractedImages: File[]; zipFile: File | null } | null> {
// Decode File
const url = URL.createObjectURL(input);
const extractedImages: File[] = [];
try {
// Wait for fully processed
@@ -27,20 +31,45 @@ export async function processPDF(input: File) {
if (fn === pdfjsLib.OPS.paintImageXObject) {
// Extract Data
const imgName = await ops.argsArray[i][0];
// Wait for the callback to finish
const img = (await new Promise((resolve) => {
page.objs.get(imgName, resolve);
})) as PdfImageObject;
// Retrieve File
const file = await processImage(img, pageNum, imageNum);
console.log('File is ', file);
}
imageNum++;
// Add into End
if (file) extractedImages.push(file);
// Add Image Counter
imageNum++;
}
}
}
// Bundle Together as Zip
// Checking the Need to Convert
if (extractedImages.length === 0) return null;
if (extractedImages.length === 1) return { extractedImages, zipFile: null };
// Converting Into Zip File
const zip = new JSZip();
extractedImages.forEach((file) => zip.file(file.name, file));
const zipBlob = await zip.generateAsync({ type: 'blob' });
const zipFile = new File([zipBlob], 'compressed-images.zip', {
type: 'application/zip'
});
if (extractedImages) {
return { extractedImages, zipFile };
} else {
return null;
}
} catch (error) {
console.log('Error processing pdf', error);
return null;
} finally {
URL.revokeObjectURL(url);
}
@@ -51,8 +80,6 @@ async function processImage(
pageNum: number,
imageNum: number
): Promise<File | null> {
console.log('Image Received is ', img);
try {
// Create Canvas
const canvas = document.createElement('canvas');