You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell修改图片拍摄日期时覆盖保存出现GDI+通用错误

解决GDI+保存图片覆盖原文件失败问题

需要批量修改硬盘照片的拍摄日期属性(计划从文件名提取日期),使用PowerShell脚本修改属性后执行Save()方法覆盖原文件时,抛出**"A generic error occurred in GDI+."**错误。尝试过克隆图片、释放原对象、调用Dispose()、设为null、重启ISE等方法,文件仍被PowerShell占用,仅能保存为新文件,希望实现直接覆盖原文件。

原脚本代码

[reflection.assembly]::LoadWithPartialName("System.Drawing")

$filePath = 'imagePath.jpg'

# Load the image as a copy
$originalPic = New-Object System.Drawing.Bitmap($filePath)
$pic = $originalPic.Clone()

# Dispose the original bitmap object to release the file handle
$originalPic.Dispose()
$originalPic = $null

$props = @("306", "20531", "36867", "36868")

$defaultDateTime = Get-Date "2018-06-28"
$dateString = $defaultDateTime.ToString("yyyy:MM:dd HH:mm:ss`0")
$byteArray = [System.Text.Encoding]::ASCII.GetBytes($dateString)

foreach($prop in $props){
    
    try{
        $propertyItem = $pic.GetPropertyItem($prop)
    }
    catch{
        $propertyItem = [System.Runtime.Serialization.FormatterServices]::GetUninitializedObject([System.Drawing.Imaging.PropertyItem])
        $propertyItem.Id = $prop
    }
    
    $propertyItem.Type = 2
    $propertyItem.Len = $byteArray.Length
    $propertyItem.Value = $byteArray

    
    $pic.SetPropertyItem($propertyItem)
}

$pic.Save($filePath)  # Save the modified image with the new property

错误信息

Exception calling "Save" with "1" argument(s): "A generic error occurred in GDI+."
At C:\Users\user\Desktop\Random Tools\Powershell\FixMyPic.ps1:40 char:1

  • $pic.Save($filePath) # Save the modified image with the new property
  • + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
      + FullyQualifiedErrorId : ExternalException
    

解决方案

核心问题是Bitmap.Clone()方法仍会保留对原文件的隐式引用,导致文件句柄未完全释放。正确做法是通过内存流中转加载图片,彻底脱离原文件依赖:

修改后的脚本

[reflection.assembly]::LoadWithPartialName("System.Drawing")

$filePath = 'imagePath.jpg'

# 读取文件到内存流,彻底释放原文件句柄
$fileStream = [System.IO.File]::OpenRead($filePath)
$memoryStream = New-Object System.IO.MemoryStream
$fileStream.CopyTo($memoryStream)
$fileStream.Dispose()

# 从内存流创建Bitmap对象,与原文件完全解耦
$pic = New-Object System.Drawing.Bitmap($memoryStream)
$memoryStream.Dispose()

# 属性ID直接用数字,避免类型转换问题
$props = @(306, 20531, 36867, 36868)

$defaultDateTime = Get-Date "2018-06-28"
$dateString = $defaultDateTime.ToString("yyyy:MM:dd HH:mm:ss`0")
$byteArray = [System.Text.Encoding]::ASCII.GetBytes($dateString)

foreach($prop in $props){
    try{
        $propertyItem = $pic.GetPropertyItem($prop)
    }
    catch{
        $propertyItem = [System.Runtime.Serialization.FormatterServices]::GetUninitializedObject([System.Drawing.Imaging.PropertyItem])
        $propertyItem.Id = $prop
    }
    
    $propertyItem.Type = 2
    $propertyItem.Len = $byteArray.Length
    $propertyItem.Value = $byteArray
    $pic.SetPropertyItem($propertyItem)
}

# 直接覆盖原文件
$pic.Save($filePath)
# 最后释放Bitmap资源,避免内存泄漏
$pic.Dispose()

关键说明

  • 用内存流加载图片后,原文件不再被占用,可直接执行覆盖保存。
  • 将属性ID从字符串改为数字,减少不必要的类型转换操作。
  • 操作完成后调用Dispose()释放Bitmap对象,避免内存泄漏。

内容的提问来源于stack exchange,提问作者AndyMcMars

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 19:42:55