我正在尝试批量编辑我保存在硬盘上的大量照片。基本上我需要更改拍摄日期的属性,以便我可以对它们进行索引。我将使用文件名来获取实际日期。
我正在使用 Powershell 编写脚本,但最后无法使其与 .save() 命令一起使用。
这是我到目前为止所写的
[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
除了最后一步我覆盖它之外,一切都工作正常。 我知道我可以给出不同的名称,这确实有效,但我不想为每个图像创建一个副本。
我以为通过 .clone 我会获得一个副本,在处理后,它只会关闭该对象,但它似乎总是在那里。
这就是我得到的错误
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
谢谢大家。
我还在处置后将其设置为 $null ,因为它似乎只是删除了属性,但对象仍然存在(我猜这是正常的),但我认为将其设置为 null 会更好。 。
我尝试关注一些 .NET 相关问题,他们使用了“using”,但我认为它不会有太大改变。
我尝试按照这个问题
打开和关闭 ISE编辑:
我还可以看到,即使使用了 dispose,图像仍然由 Powershell 保存,这就是它阻止覆盖的原因
您当前的方法 - 将文件路径传递给
[Bitmap]
构造函数,然后克隆生成的对象 - 似乎还克隆创建的文件句柄,导致当您调用 $pic.Save
时发生共享冲突,就像现在 $pic
本身一样对同一文件有读锁。
$originalPic = New-Object System.Drawing.Bitmap($filePath) # exclusive read handle count: 1
$pic = $originalPic.Clone() # exclusive read handle count: 2
$originalPic.Dispose() # exclusive read handle count: 1
$originalPic = $null # still not in the clear...
在幕后,所有文件系统 I/O 均由 Windows 的本机 GDI+ API 处理,因此您会收到“通用 GDI+ 错误”,因为它无法完成文件写入,并且不知道这是因为调用应用程序有文件的独占句柄。
要解决此问题,请使用
[Image]::FromFile
加载原始图片,然后将生成的图像对象传递给 [Bitmap]
构造函数 - 此时构造函数将从内存中对象复制图像数据,而不是重新创建文件句柄,在处理原始文件后,您应该可以自由地获取该文件的写入句柄:
$originalPic = [System.Drawing.Image]::FromFile($filePath) # exclusive read handle count: 1
$pic = [System.Drawing.Bitmap]::new($originalPic) # exclusive read handle count: 1
$originalPic.Dispose() # exclusive read handle count: 0