在 PowerShell 中提取 EXIF 数据的简单方法?

Kar*_*eem 6 powershell exif image date

我一直在研究使用 PowerShell 提取 EXIF 数据的各种方法,但到目前为止我发现它相当复杂。一些在这里这里

我正在寻找一种(相对)简单的方法来使用 powershell 提取基本 EXIF 数据,以便我可以在本机使用它。

特别是,我对“拍摄日期”属性特别感兴趣,并且我正在尝试找到一种可以通过Get-Date运行该属性的方法,并根据自己的需要自定义格式。就像是:

$exifdatetaken = $mypicture.'Date taken' | Get-Date -Format yyyyMMdd-HHmmss
Run Code Online (Sandbox Code Playgroud)

有谁知道是否有办法在 PowerShell 中本地执行此操作?

nmb*_*ell 4

提取 EXIF 元数据通常如此复杂的原因是因为图像元数据作为文件内容的一部分存储(与文件元数据相反,文件元数据由操作系统与文件分开存储和索引)。除此之外,EXIF 是一种可扩展格式,制造商经常使用(并滥用)以专有格式存储数据,这种情况很快就会变得混乱。

\n

您链接到的两个参考都使用[System.Drawing]GDI+ Win32 API 中的类,该 API 公开了 200 多个图像属性,其中多个属性可能反映拍摄照片的日期时间。它们还对单个属性36867 (0x9003)(即PropertyTagExifDTOrig值)进行硬编码。

\n

利用该类[System.Drawing.Bitmap]来公开所有可用的元数据非常简单,例如:

\n
$path   = \'C:\\my\\images\\Canon.jpg\'\n$bitmap = [System.Drawing.Bitmap]::new($path)\n$bitmap.PropertyItems\n
Run Code Online (Sandbox Code Playgroud)\n

这将给出一组如下结果:

\n
   Id  Len Type Value\n   --  --- ---- -----\n  271    6    2 {67, 97, 110, 111, 110, 0}\n  272   24    2 {67, 97, 110, 111, 110, 32, 69, 79, 83, 32\xe2\x80\xa6}\n  274    2    3 {1, 0}\n  282    8    5 {180, 0, 0, 0, 1, 0, 0, 0}\n  283    8    5 {180, 0, 0, 0, 1, 0, 0, 0}\n  296    2    3 {2, 0}\n  306   20    2 {50, 48, 48, 51, 58, 49, 50, 58, 48, 52\xe2\x80\xa6}\n  531    2    3 {1, 0}\n33434    8    5 {4, 0, 0, 0, 1, 0, 0, 0}\n33437    8    5 {14, 0, 0, 0, 1, 0, 0, 0}\n34855    2    3 {100, 0}\n36864    4    7 {48, 50, 50, 49}\n# etc.\n
Run Code Online (Sandbox Code Playgroud)\n

这是最简单的部分。从这些数据中获取有用的东西才是棘手的地方。引用属性标签Id来告诉您正在查看哪个属性。这是一个字节数组,需要解码为有意义的值(其本身可能是一个或两个步骤的过程)。要了解如何解码字节,您需要查看可用于查找数据类型的值。一旦你解码了字节,你可能会剩下:ValueType

\n
    \n
  • 有意义的值(例如包含相机制造商名称的 ASCII 字符串)
  • \n
  • 一个值,该值是对EXIF 标准中查找的引用(例如,对于 Id 37383 (0x9207 PropertyTagExifMeteringMode),值 0 表示“未知”,1 表示“平均”,依此类推),或者需要一些额外的计算才能获得有意义的值
  • \n
  • 可以从某些外部参考(例如ExifTool\ 的标签列表)解码的未知值
  • \n
  • 无法解码的未知值(或者需要原始软件来解码)
  • \n
\n

例如,要使用 Id 306 (0x0132 PropertyTagDateTime) 获取图像创建的日期和时间(ASCII 字符串),如下所示:

\n
$pi        = $bitmap.GetPropertyItem(306)\n$ascii     = [System.Text.ASCIIEncoding]::new()\n$piDecoded = $ascii.GetString($pi.Value[0..$($pi.Len-2)]) # trim off the trailing null terminator\n$piDecoded\n$piDecoded.GetType().FullName\n\n
Run Code Online (Sandbox Code Playgroud)\n

返回例如:

\n
2022:06:11 13:25:36\nSystem.String\n
Run Code Online (Sandbox Code Playgroud)\n

然后,您可以直接将其处理为您想要的格式,或者解析它并将其发送到 Get-Date 以获取 DateTime 对象。

\n

另一个示例,要使用 Id 34855 (0x8827 PropertyTagExifISOSpeed) 获取图像(SHORT (UInt16) 类型)的 ISO:

\n
$pi        = $bitmap.GetPropertyItem(34855)\n$piDecoded = [System.BitConverter]::ToUInt16($pi.Value,0)\n$piDecoded\n$piDecoded.GetType().FullName\n
Run Code Online (Sandbox Code Playgroud)\n

返回例如:

\n
100\nSystem.UInt16\n
Run Code Online (Sandbox Code Playgroud)\n

等等。

\n

我本来想解决完全相同的问题,主要是对我的个人存档中的图像进行大规模重命名,同时也希望有一种简单的方法来过滤图像,例如基于图像方向(我将其内置到 PowerShell 模块中) 。你可以在这篇文章中看到我上面描述的逻辑的具体实现

\n