如何在ReactJS客户端提取Excel工作表中的浮动图片?
客户端提取Excel浮动图片的可行方案
以下是几种纯客户端(或Node.js环境)实现的方案,无需依赖服务端:
方案1:使用ExcelJS库
ExcelJS原生支持识别工作表中的浮动图片,处理逻辑简单直接:
- 安装依赖:
npm install exceljs
- 提取图片的代码示例:
const ExcelJS = require('exceljs'); const fs = require('fs'); async function extractFloatingImages(filePath) { const workbook = new ExcelJS.Workbook(); await workbook.xlsx.readFile(filePath); // 遍历所有工作表 for (const worksheet of workbook.worksheets) { // 检查当前工作表是否有浮动图片 if (!worksheet.drawings || worksheet.drawings.length === 0) continue; worksheet.drawings.forEach((drawing, idx) => { if (drawing.image) { // 保存图片到本地 const savePath = `float_img_${worksheet.name}_${idx}.${drawing.image.extension}`; fs.writeFileSync(savePath, drawing.image.buffer); } }); } } // 调用示例 extractFloatingImages('your_file.xlsx');
方案2:SheetJS结合手动解析XLSX内部结构
SheetJS本身不直接提取浮动图片,但可以借助它读取XLSX的内部文件结构,手动解析绘图相关的XML文件来定位图片:
- 安装依赖:
npm install xlsx xml2js
- 实现代码:
const XLSX = require('xlsx'); const xml2js = require('xml2js'); const fs = require('fs'); async function extractImagesWithSheetJS(filePath) { const workbook = XLSX.readFile(filePath, { type: 'file' }); const parser = new xml2js.Parser(); // 遍历工作表对应的绘图文件 for (const sheetName of workbook.SheetNames) { const sheet = workbook.Sheets[sheetName]; const drawingId = sheet['!drawing']; if (!drawingId) continue; // 获取绘图XML文件和对应的关系文件 const drawingXml = workbook.files[`xl/drawings/drawing${drawingId}.xml`].data.toString(); const relsXml = workbook.files[`xl/drawings/_rels/drawing${drawingId}.xml.rels`].data.toString(); // 解析关系文件,映射rId到图片路径 const relsResult = await parser.parseStringPromise(relsXml); const rIdMap = {}; relsResult.Relationships.Relationship.forEach(rel => { rIdMap[rel.$.Id] = rel.$.Target; }); // 解析绘图XML,提取图片对应的rId const drawingResult = await parser.parseStringPromise(drawingXml); const blips = drawingResult['xdr:wsDr']['xdr:twoCellAnchor']?.map(anchor => { return anchor['xdr:pic']?.[0]['xdr:blipFill']?.[0]['a:blip']?.[0]['$']['r:embed']; }).filter(Boolean); // 提取并保存图片 blips.forEach((rId, idx) => { const imgPath = `xl/${rIdMap[rId]}`; const imgBuffer = workbook.files[imgPath].data; const ext = imgPath.split('.').pop(); fs.writeFileSync(`sheet_${sheetName}_img_${idx}.${ext}`, imgBuffer); }); } } // 调用示例 extractImagesWithSheetJS('your_file.xlsx');
方案3:直接解析XLSX压缩包
XLSX本质是ZIP格式文件,可通过JSZip直接解压后读取内部的绘图和媒体文件:
- 安装依赖:
npm install jszip xml2js
- 实现代码:
const JSZip = require('jszip'); const xml2js = require('xml2js'); const fs = require('fs'); async function extractImagesFromZip(filePath) { const zipData = fs.readFileSync(filePath); const zip = await JSZip.loadAsync(zipData); const parser = new xml2js.Parser(); // 遍历所有绘图文件 const drawingFiles = Object.keys(zip.files).filter(path => path.startsWith('xl/drawings/drawing') && path.endsWith('.xml')); for (const drawingPath of drawingFiles) { // 读取绘图XML和对应的关系文件 const drawingXml = await zip.file(drawingPath).async('string'); const relsPath = drawingPath.replace('.xml', '.xml.rels'); const relsXml = await zip.file(relsPath).async('string'); // 解析关系文件 const relsResult = await parser.parseStringPromise(relsXml); const rIdToTarget = relsResult.Relationships.Relationship.reduce((map, rel) => { map[rel.$.Id] = rel.$.Target; return map; }, {}); // 解析绘图XML获取图片rId const drawingResult = await parser.parseStringPromise(drawingXml); const imageRIds = drawingResult['xdr:wsDr']['xdr:twoCellAnchor']?.reduce((ids, anchor) => { const blip = anchor['xdr:pic']?.[0]['xdr:blipFill']?.[0]['a:blip']?.[0]; if (blip?.$?.['r:embed']) ids.push(blip.$['r:embed']); return ids; }, []) || []; // 提取并保存图片 imageRIds.forEach((rId, idx) => { const imgTarget = rIdToTarget[rId]; if (!imgTarget) return; zip.file(`xl/${imgTarget}`).async('nodebuffer').then(imgBuffer => { const ext = imgTarget.split('.').pop(); fs.writeFileSync(`extracted_img_${idx}.${ext}`, imgBuffer); }); }); } } // 调用示例 extractImagesFromZip('your_file.xlsx');
以上方案均支持在Node.js环境(客户端侧运行)或浏览器环境(调整文件读取逻辑为File API)实现,无需依赖服务端。
内容的提问来源于stack exchange,提问作者Mohsin
相关产品推荐
相关产品推荐

