我一直在寻找可以使用 PowerShell 提取 EXIF 数据的各种方法,但到目前为止我发现它非常复杂。 一些here和 here .
我正在寻找一种(相对)简单的方法来使用 powershell 提取基本 EXIF 数据,以便我可以在 native 使用它。
特别是,我对 Date Taken 属性特别感兴趣,我正在尝试找到一种方法,我可以通过 Get-Date 运行它,并自定义格式为了我自己的需要。 像这样的东西:
$exifdatetaken = $mypicture.'Date taken' | Get-Date -Format yyyyMMdd-HHmmss
有谁知道是否有办法在 PowerShell 中本地执行此操作?
最佳答案
提取 EXIF 元数据通常如此复杂的原因是因为 image 元数据作为文件内容的一部分存储(与 file 元数据相反,它存储并由操作系统与文件分开索引)。除此之外,EXIF 是一种可扩展格式,制造商经常使用(和滥用)这种格式来以专有格式存储数据,因此情况很快就会变得困惑。
您链接的两个引用都使用来自 GDI+ Win32 API 的 [System.Drawing]
类,它公开了 200 多个图像属性,其中不止一个可能反射(reflect)了图片的日期时间采取。它们还针对单个属性 36867 (0x9003)
进行硬编码,这是 PropertyTagExifDTOrig
值。
利用 [System.Drawing.Bitmap]
类来公开所有可用的元数据相当简单,例如:
$path = 'C:\my\images\Canon.jpg'
$bitmap = [System.Drawing.Bitmap]::new($path)
$bitmap.PropertyItems
这将给出一组这样的结果:
Id Len Type Value
-- --- ---- -----
271 6 2 {67, 97, 110, 111, 110, 0}
272 24 2 {67, 97, 110, 111, 110, 32, 69, 79, 83, 32…}
274 2 3 {1, 0}
282 8 5 {180, 0, 0, 0, 1, 0, 0, 0}
283 8 5 {180, 0, 0, 0, 1, 0, 0, 0}
296 2 3 {2, 0}
306 20 2 {50, 48, 48, 51, 58, 49, 50, 58, 48, 52…}
531 2 3 {1, 0}
33434 8 5 {4, 0, 0, 0, 1, 0, 0, 0}
33437 8 5 {14, 0, 0, 0, 1, 0, 0, 0}
34855 2 3 {100, 0}
36864 4 7 {48, 50, 50, 49}
# etc.
这是简单的部分。从这些数据中获取有用的东西是棘手的。 Id
引用 property tag告诉您您正在查看的特性。 Value
是一个字节数组,需要将其解码为有意义的值(它本身可能是一个或两个步骤的过程)。要了解如何解码字节,您需要查看可用于查找 data type 的 Type
值。 .一旦你解码了字节,你可能会留下:
- 一个有意义的值(例如,包含相机制造商名称的 ASCII 字符串)
- 一个值,它是对 EXIF standard 中查找的引用(例如,对于 Id 37383 (0x9207 PropertyTagExifMeteringMode),值 0 表示“未知”,1 表示“平均”,依此类推),或者需要一些额外的计算才能获得有意义的值
- 可以从一些外部引用(例如 ExifTool's list of tags)解码的未知值
- 无法解码(或需要原始软件解码)的未知值
例如,要使用 Id 306 (0x0132 PropertyTagDateTime) 获取创建图像的日期和时间(ASCII 字符串),如下所示:
$pi = $bitmap.GetPropertyItem(306)
$ascii = [System.Text.ASCIIEncoding]::new()
$piDecoded = $ascii.GetString($pi.Value[0..$($pi.Len-2)]) # trim off the trailing null terminator
$piDecoded
$piDecoded.GetType().FullName
返回例如:
2022:06:11 13:25:36
System.String
然后您可以直接将其操作成您想要的格式,或者解析它并将其发送到 Get-Date 以获取 DateTime 对象。
另一个示例,使用 Id 34855 (0x8827 PropertyTagExifISOSpeed) 获取图像(SHORT (UInt16) 类型)的 ISO:
$pi = $bitmap.GetPropertyItem(34855)
$piDecoded = [System.BitConverter]::ToUInt16($pi.Value,0)
$piDecoded
$piDecoded.GetType().FullName
返回例如:
100
System.UInt16
等等。
我曾想解决完全相同的问题,主要是对我的个人文件中的图像进行大量重命名,但也有一种简单的方法来过滤图像,例如,我内置的图像方向一个 PowerShell 模块。你可以在this中看到我上面描述的逻辑的具体实现。功能。
关于image - 在 PowerShell 中提取 EXIF 数据的简便方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34913250/