之前对 docx 文档困扰的问题,现象表现为——
无法显示链接的图像。该文件可能已被移动、重命名或删除。请验证该链接是否指向正确的文件和位置。
The linked image cannot be displayed. The file may have been moved, renamed, or deleted. Verify that the link points to the correct file and location.
先前,wps文字表格邮件附件部分图片无法预览的问题(1),提到的问题,没想到简单的编辑指向文件的链接方法就能解决。
文件-信息-编辑指向文件的链接,选中将文件保存在文档中,以及选中待处理的链接条目,断开链接。
vba 查看图片源文件路径与转换链接
Sub DisplayLinkedImageNameAndUnlink()
Dim shp As Shape
' 打印内联形状和形状的数量
Debug.Print "InlineShapes Count: " & ActiveDocument.InlineShapes.Count
Debug.Print "Shapes Count: " & ActiveDocument.Shapes.Count
' 遍历形状集合
For Each shp In ActiveDocument.Shapes
With shp
' 检查形状是否为链接的图片
If shp.Type = msoLinkedPicture Then
' 打印源文件名、备选文本和名称
Debug.Print "Target: " & shp.LinkFormat.SourceFullName
Debug.Print "descr: " & shp.AlternativeText
Debug.Print "Name: " & shp.Name
'更新链接
shp.LinkFormat.Update
shp.LinkFormat.SavePictureWithDocument = True
' 解除链接
shp.LinkFormat.BreakLink
ActiveDocument.UndoClear
End If
End With
Next
' 遍历内联形状集合
For j = ActiveDocument.InlineShapes.Count To 1 Step -1
' 检查内联形状是否为链接的图片
If ActiveDocument.InlineShapes(j).Type = wdInlineShapeLinkedPicture Then
' 打印备选文本和源文件名
Debug.Print "descr: " & ActiveDocument.InlineShapes(j).AlternativeText
Debug.Print "Target: " & ActiveDocument.InlineShapes(j).LinkFormat.SourceFullName
ActiveDocument.InlineShapes(j).LinkFormat.Update
' unlink the inlineshape picture
ActiveDocument.InlineShapes(j).LinkFormat.SavePictureWithDocument = True
ActiveDocument.InlineShapes(j).LinkFormat.BreakLink
ActiveDocument.UndoClear
End If
Next j
'保存当前活动文档
ActiveDocument.Save
End Sub
使用 Powershell 的一些练习
# 打开Word文档作为一个压缩包
$WordPackage = [System.IO.Packaging.Package]::Open("C:\Users\demo\问题-无法显示链接的图片.docx")
# 定义一个函数,用于从压缩包中提取指定部分的内容
function Get-ZipPart {
param (
[string]$PartUri
)
$dataStream = New-Object System.IO.MemoryStream
$WordPackage.GetPart($PartUri).GetStream().CopyTo($dataStream)
return [System.Text.Encoding]::UTF8.GetString($dataStream.ToArray())
}
# 提取 document.xml.rels 中的关系信息
$Relationships = Get-ZipPart "/word/_rels/document.xml.rels" | Select-Xml -XPath "//ns:Relationship/@Id | //ns:Relationship/@Target" -Namespace @{ns='http://schemas.openxmlformats.org/package/2006/relationships'} | ForEach-Object { $_.Node.Value }
# 提取 document.xml 中的图片描述信息
$ImageDescriptions = Get-ZipPart "/word/document.xml" | Select-Xml -XPath "//pic:cNvPr/@descr" -Namespace @{pic='http://schemas.openxmlformats.org/drawingml/2006/picture'} | ForEach-Object { $_.Node."#text" }
# 输出结果
$Relationships
$ImageDescriptions
再进一步,由 大语言模型 Claude 深化一下,则有,
# 定义命名空间
$namespaces = @{
rel = 'http://schemas.openxmlformats.org/package/2006/relationships'
pic = 'http://schemas.openxmlformats.org/drawingml/2006/picture'
a = 'http://schemas.openxmlformats.org/drawingml/2006/main'
wp = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'
}
function Get-WordPackage {
param (
[Parameter(Mandatory=$true)]
[string]$FilePath
)
try {
return [System.IO.Packaging.Package]::Open($FilePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
}
catch {
Write-Error "无法打开文件: $FilePath"
Write-Error $_.Exception.Message
return $null
}
}
function Get-PackagePartContent {
param (
[Parameter(Mandatory=$true)]
[System.IO.Packaging.Package]$Package,
[Parameter(Mandatory=$true)]
[string]$PartPath
)
try {
$part = $Package.GetPart($PartPath)
$stream = New-Object System.IO.MemoryStream
$part.GetStream().CopyTo($stream)
return [System.Text.Encoding]::UTF8.GetString($stream.ToArray())
}
catch {
Write-Error "无法读取部分: $PartPath"
Write-Error $_.Exception.Message
return $null
}
}
function Get-ImageRelationships {
param (
[Parameter(Mandatory=$true)]
[System.IO.Packaging.Package]$Package
)
$relsContent = Get-PackagePartContent -Package $Package -PartPath "/word/_rels/document.xml.rels"
if ($relsContent) {
$relationships = Select-Xml -Content $relsContent -XPath "//rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/image']" -Namespace $namespaces
return $relationships | ForEach-Object {
@{
Id = $_.Node.Id
Target = $_.Node.Target
TargetMode = $_.Node.TargetMode
}
}
}
return $null
}
function Get-ImageDescriptions {
param (
[Parameter(Mandatory=$true)]
[System.IO.Packaging.Package]$Package
)
$docContent = Get-PackagePartContent -Package $Package -PartPath "/word/document.xml"
if ($docContent) {
return Select-Xml -Content $docContent -XPath "//pic:cNvPr" -Namespace $namespaces | ForEach-Object {
@{
Id = $_.Node.id
Name = $_.Node.name
Description = $_.Node.descr
}
}
}
return $null
}
function Get-WordImageInfo {
param (
[Parameter(Mandatory=$true)]
[string]$FilePath
)
$package = Get-WordPackage -FilePath $FilePath
if (-not $package) { return }
try {
Write-Host "=== Word文档图片信息 ===" -ForegroundColor Green
Write-Host "文件: $FilePath" -ForegroundColor Green
Write-Host "------------------------"
# 获取图片关系
Write-Host "`n图片关系:" -ForegroundColor Yellow
$relationships = Get-ImageRelationships -Package $package
$relationships | ForEach-Object {
Write-Host "ID: $($_.Id)"
Write-Host "目标: $($_.Target)"
if ($_.TargetMode) {
Write-Host "目标模式: $($_.TargetMode)"
}
Write-Host "------------------------"
}
# 获取图片描述
Write-Host "`n图片描述:" -ForegroundColor Yellow
$descriptions = Get-ImageDescriptions -Package $package
$descriptions | ForEach-Object {
Write-Host "ID: $($_.Id)"
Write-Host "名称: $($_.Name)"
if ($_.Description) {
Write-Host "描述: $($_.Description)"
}
Write-Host "------------------------"
}
# 检查链接图片
Write-Host "`n链接状态检查:" -ForegroundColor Yellow
$relationships | Where-Object { $_.TargetMode -eq 'External' } | ForEach-Object {
$target = $_.Target
if (Test-Path $target) {
Write-Host "链接正常: $target" -ForegroundColor Green
}
else {
Write-Host "链接断开: $target" -ForegroundColor Red
}
Write-Host "------------------------"
}
}
finally {
$package.Close()
}
}
# 使用示例
# Get-WordImageInfo -FilePath "C:\Users\demo\Documents\question_images.docx"
P.s. 有一个现象是,本地链接中长路径会用 8.3 短文件名命名规则,如果原来的路径丢失,可以重建路径(需要注意访问权限),同时文件内容就未必和原始的一致了。使用 dir /x 命令可以查看短地址,单行命令 for %i in ("C:\Program Files") do @echo %~si,或者用 powershell,比如 (New-Object -com scripting.filesystemobject).getfolder('C:\Program Files').shortname 得到 Program Files 的短路径 PROGRA~1。
搜索“AppData\Local\Temp\ksohtml\clip_image”,可以发现网上有许多错误使用 wps 文档(没有转换为非链接图片)复制粘贴而造成图片无法显示而影响正常阅读的。
参考或延申阅读:
Transform linked images to embedded images
Break link to picture programatically in MS Word 2010
How to convert all linked images to embedded in Word document?
PPT中用vba批量断开外部链接及更改链接路径的方法
8.3 Filename
How can I find the short path of a Windows directory/file?