詳解如何利用PowerShell提取wps表格中嵌入的圖片
針對Excel下打開表格圖片顯示 #NAME?編輯欄顯示為 =@_xlfn.DISPIMG( 樣公式的問題,一般需要在 wps 程序下,Ctrl+F 查找范圍選值,輸入 =DISPIMG 全選,然后再右鍵轉(zhuǎn)換為浮動圖片。如果是Excel中,則是查找公式 DISPIMG。
查閱網(wǎng)上得資料得知,可以通過解壓表格文件,然后 根據(jù)公式中的第一參數(shù)(通常以 ID 開頭)看 xl_rels\cellimages.xml.rels 目錄下的 name (其值為 dispimg 函數(shù)的第一參數(shù))和 r:embed (其值以 rId 開頭)的對應(yīng)關(guān)系,然后再看 Id ( rId 開頭 ) 和 Target(圖片路徑) 的對應(yīng)關(guān)系,進(jìn)而得到圖片的路徑。
在 LLM 的幫助下進(jìn)而有以下 PS 腳本。
function Get-ExcelDispImages { param ( [Parameter(Mandatory=$true)] [string]$ExcelPath, [Parameter(Mandatory=$false)] [string]$OutputFolder = ".\ExcelImages" ) # 輔助函數(shù):安全地讀取文件內(nèi)容 function Read-FileContent { param ( [string]$Path ) try { # 使用.NET方法直接讀取文件,避免PowerShell路徑解析問題 if ([System.IO.File]::Exists($Path)) { return [System.IO.File]::ReadAllText($Path) } Write-Host "File not found: $Path" -ForegroundColor Yellow return $null } catch { Write-Host "Error reading file $Path : $_" -ForegroundColor Yellow return $null } } try { # 驗證Excel文件是否存在 if (-not (Test-Path -LiteralPath $ExcelPath)) { throw "Excel file not found: $ExcelPath" } # 確保ExcelPath是絕對路徑 $ExcelPath = (Get-Item $ExcelPath).FullName # 創(chuàng)建輸出文件夾(使用絕對路徑) $OutputFolder = [System.IO.Path]::GetFullPath($OutputFolder) if (-not (Test-Path -Path $OutputFolder)) { New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null } # 創(chuàng)建Excel COM對象 $excel = New-Object -ComObject Excel.Application $excel.Visible = $false $excel.DisplayAlerts = $false $workbook = $excel.Workbooks.Open($ExcelPath) # 用于存儲找到的DISPIMG ID和信息 $dispImgIds = @() $imageMapping = @{} # 遍歷所有工作表 foreach ($worksheet in $workbook.Worksheets) { $usedRange = $worksheet.UsedRange $rowCount = $usedRange.Rows.Count $colCount = $usedRange.Columns.Count for ($row = 1; $row -le $rowCount; $row++) { for ($col = 1; $col -le $colCount; $col++) { $cell = $usedRange.Cells($row, $col) $formula = $cell.Formula # 檢查是否包含DISPIMG函數(shù)并提取所有參數(shù) if ($formula -match 'DISPIMG\("([^"]+)"') { $imageId = $matches[1] Write-Host "Found DISPIMG: $formula" -ForegroundColor Gray # 創(chuàng)建參數(shù)列表 $params = @{ 'ID' = $imageId 'Cell' = $cell.Address() 'Formula' = $formula 'Worksheet' = $worksheet.Name } # 提取所有參數(shù),包括圖片ID $paramValues = @() $formula -match 'DISPIMG\((.*?)\)' | Out-Null $paramString = $matches[1] $paramValues = $paramString -split ',' | ForEach-Object { $_ -replace '"', '' -replace '^\s+|\s+$', '' } # 存儲所有參數(shù) for ($i = 0; $i -lt $paramValues.Count; $i++) { $params["Param$i"] = $paramValues[$i] } $imageMapping[$imageId] = $params $dispImgIds += $imageId } } } } # 創(chuàng)建臨時目錄 $tempPath = Join-Path ([System.IO.Path]::GetTempPath()) "ExcelTemp" if (Test-Path $tempPath) { Remove-Item $tempPath -Recurse -Force } New-Item -ItemType Directory -Path $tempPath -Force | Out-Null # 復(fù)制Excel文件到臨時目錄并解壓 $tempExcel = Join-Path $tempPath "temp.xlsx" $tempZip = Join-Path $tempPath "temp.zip" Copy-Item -Path $ExcelPath -Destination $tempExcel -Force if (Test-Path $tempZip) { Remove-Item $tempZip -Force } Rename-Item -Path $tempExcel -NewName "temp.zip" -Force Expand-Archive -Path $tempZip -DestinationPath $tempPath -Force # 檢查media文件夾并處理圖片 $mediaPath = Join-Path $tempPath "xl\media" if (Test-Path $mediaPath) { # 顯示DISPIMG參數(shù)和圖片對應(yīng)關(guān)系 Write-Host "`nFound $($imageMapping.Count) DISPIMG functions" -ForegroundColor Cyan if ($imageMapping.Count -gt 0) { Write-Host "`n=== DISPIMG Functions Found ===" -ForegroundColor Cyan Write-Host "Found $($imageMapping.Count) DISPIMG functions" -ForegroundColor Cyan # 顯示所有找到的DISPIMG函數(shù) Write-Host "`n=== DISPIMG Functions Details ===" -ForegroundColor Yellow foreach ($id in $imageMapping.Keys) { $params = $imageMapping[$id] Write-Host "Cell: [$($params.Worksheet)]$($params.Cell)" -ForegroundColor Gray Write-Host "Formula: $($params.Formula)" -ForegroundColor Gray } # 首先從cellimages.xml獲取DISPIMG ID到rId的映射 $dispImgToRid = @{} $cellImagesPath = Join-Path $tempPath "xl\cellimages.xml" Write-Host "`n=== Reading cellimages.xml ===" -ForegroundColor Yellow Write-Host "Path: $cellImagesPath" -ForegroundColor Gray if (Test-Path $cellImagesPath) { try { $xmlContent = Get-Content $cellImagesPath -Raw -EnCoding UTF8 Write-Host "`nRaw XML Content:" -ForegroundColor Gray Write-Host $xmlContent # 使用正則表達(dá)式提取所有cellImage元素 $matches = [regex]::Matches($xmlContent, '<etc:cellImage>.*?</etc:cellImage>', [System.Text.RegularExpressions.RegexOptions]::Singleline) Write-Host "`nFound $($matches.Count) cellImage elements" -ForegroundColor Gray foreach ($match in $matches) { $cellImageXml = $match.Value Write-Host "`nProcessing cellImage element:" -ForegroundColor Gray # 提取name屬性(包含DISPIMG ID) if ($cellImageXml -match 'name="([^"]+)"') { $dispImgId = $matches[1] Write-Host "Found DISPIMG ID: $dispImgId" -ForegroundColor Gray # 提取r:embed屬性(包含rId) if ($cellImageXml -match 'r:embed="(rId\d+)"') { $rId = $matches[1] $dispImgToRid[$dispImgId] = $rId Write-Host " Mapping: DISPIMG ID $dispImgId -> rId $rId" -ForegroundColor Green } } } } catch { Write-Host "Error reading cellimages.xml: $($_.Exception.Message)" -ForegroundColor Red Write-Host $_.Exception.StackTrace -ForegroundColor Red } } else { Write-Host "cellimages.xml not found!" -ForegroundColor Red } # 從cellimages.xml.rels獲取rId到實際圖片的映射 $ridToImage = @{} $cellImagesRelsPath = Join-Path $tempPath "xl\_rels\cellimages.xml.rels" Write-Host "`n=== Reading cellimages.xml.rels ===" -ForegroundColor Yellow Write-Host "Path: $cellImagesRelsPath" -ForegroundColor Gray if (Test-Path $cellImagesRelsPath) { try { [xml]$relsXml = Get-Content $cellImagesRelsPath -Raw Write-Host "`nXML Content:" -ForegroundColor Gray Write-Host $relsXml.OuterXml $relsXml.Relationships.Relationship | ForEach-Object { if ($_.Target -match "media/") { $ridToImage[$_.Id] = $_.Target Write-Host " rId $($_.Id) -> $($_.Target)" -ForegroundColor Green } } } catch { Write-Host "Error reading cellimages.xml.rels: $($_.Exception.Message)" -ForegroundColor Red Write-Host $_.Exception.StackTrace -ForegroundColor Red } } else { Write-Host "cellimages.xml.rels not found!" -ForegroundColor Red } Write-Host "`n=== Summary of Mappings ===" -ForegroundColor Yellow Write-Host "DISPIMG ID -> rId mappings:" -ForegroundColor Gray $dispImgToRid.GetEnumerator() | ForEach-Object { Write-Host " $($_.Key) -> $($_.Value)" -ForegroundColor Gray } Write-Host "`nrId -> Image mappings:" -ForegroundColor Gray $ridToImage.GetEnumerator() | ForEach-Object { Write-Host " $($_.Key) -> $($_.Value)" -ForegroundColor Gray } # 處理每個DISPIMG函數(shù) Write-Host "`n=== Processing DISPIMG Functions ===" -ForegroundColor Yellow foreach ($id in $imageMapping.Keys) { $params = $imageMapping[$id] Write-Host "`nProcessing: [$($params.Worksheet)]$($params.Cell)" -ForegroundColor Green Write-Host "Formula: $($params.Formula)" -ForegroundColor Gray Write-Host "DISPIMG ID: $id" -ForegroundColor Gray # 從DISPIMG ID查找對應(yīng)的rId $rId = $dispImgToRid[$id] if ($rId) { Write-Host "Found rId: $rId" -ForegroundColor Green # 從rId查找對應(yīng)的圖片路徑 $imagePath = $ridToImage[$rId] if ($imagePath) { Write-Host "Found image path: $imagePath" -ForegroundColor Green $imageName = Split-Path $imagePath -Leaf # 查找對應(yīng)的圖片文件 $mediaFile = Get-ChildItem -LiteralPath $mediaPath | Where-Object { $_.Name -eq $imageName } if ($mediaFile) { $outputPath = Join-Path $OutputFolder "$id$($mediaFile.Extension)" Copy-Item -LiteralPath $mediaFile.FullName -Destination $outputPath -Force Write-Host "Successfully copied: $imageName -> $outputPath" -ForegroundColor Cyan # 以 media 文件夾下的文件名復(fù)制 # Copy-Item $mediaFile.FullName $(Join-Path $OutputFolder $(Split-Path $imagePath -Leaf)) } else { Write-Host "Image file not found: $imageName" -ForegroundColor Red } } else { Write-Host "No image path found for rId: $rId" -ForegroundColor Red } } else { Write-Host "No rId found for DISPIMG ID: $id" -ForegroundColor Red } } } else { Write-Host "No DISPIMG functions found in the workbook." -ForegroundColor Yellow } } } catch { Write-Host "錯誤: $($_.Exception.Message)" -ForegroundColor Red } finally { # 清理 if ($workbook) { $workbook.Close($false) } if ($excel) { $excel.Quit() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null } if (Test-Path $tempPath) { Remove-Item $tempPath -Recurse -Force } [System.GC]::Collect() [System.GC]::WaitForPendingFinalizers() } }
一個可能的用法如下
Get-ExcelDispImages -ExcelPath "C:\Users\demo\Documents\dispimg_wps.xlsx" -OutputFolder $pwd\output
生成的圖片在當(dāng)前目錄下的 output 文件夾下。
以上就是詳解如何利用PowerShell提取wps表格中嵌入的圖片的詳細(xì)內(nèi)容,更多關(guān)于PowerShell提取表格中圖片的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PowerShell中獲取Windows系統(tǒng)序列號的腳本分享
這篇文章主要介紹了PowerShell中獲取Windows系統(tǒng)序列號的腳本分享,本文方法是讀取注冊表中的信息,然后處理成序列號輸出,需要的朋友可以參考下2014-11-11Powershell展開對象數(shù)據(jù)結(jié)構(gòu)并以JSON格式輸出
這篇文章主要介紹了Powershell展開對象數(shù)據(jù)結(jié)構(gòu)并以JSON格式輸出,本文直接給出實現(xiàn)代碼,需要的朋友可以參考下2015-03-03PowerShell重啟服務(wù)命令Restart-Service詳細(xì)介紹
這篇文章主要介紹了PowerShell重啟服務(wù)命令Restart-Service詳細(xì)介紹,Restart-Service命令主要用來重啟一些系統(tǒng)級的服務(wù),需要的朋友可以參考下2014-08-08PowerShell入門教程之創(chuàng)建和使用配置文件實例
這篇文章主要介紹了PowerShell入門教程之創(chuàng)建和使用配置文件實例,PowerShell的配置文件都是些普通的PowerShell腳本文件,需要的朋友可以參考下2014-10-10PowerShell面向?qū)ο缶幊袒A(chǔ)知識總結(jié)
這篇文章主要介紹了PowerShell面向?qū)ο缶幊袒A(chǔ)知識總結(jié),本文著重講解面向?qū)ο蟮囊恍└拍?又給出了Get-Member命令輸出類的屬性和方法的例子,需要的朋友可以參考下2014-08-08PowerShell小技巧之配置機(jī)器的靜態(tài)IP
本文主要介紹了利用PowerShell配置靜態(tài)IP地址的方法以及示例,有需要的朋友參考下2014-09-09