# encoding: ascii
# api: powershell
# title: Get-ImageMetaData
# description: Get-ImageMetadata lets you access the EXIF, XMP and other metadata about image files … this should only be taken as an example and a reference, not for solid production work — in other words, I won’t take the blame if you zero out all your jpgs trying to modify this to ReadWrite instead of just Read :)
# version: 1.0
# type: function
# author: Joel Bennett
# license: CC0
# function: Get-ImageMetadata
# x-poshcode-id: 2616
# x-archived: 2014-10-15T14:49:03
# x-published: 2011-04-15T11:53:00
#
#
function Get-ImageMetadata {
#.Synopsis
# pull EXIF, XMP, and other data from images using the BitmapMetaData
#.Example
# $image = Get-ImageMetadata C:\Users\JBennett\Pictures\3200x1200\02179_piertonowhere_interfacelift_com.jpg -verbose
# $image | fl *tiff*
# $image | fl *exif*
## Usage: ls *.jpg | Get-ImageMetaData | ft Length, LastWriteTime, Name, "36867"
## Note that '36867' is the decimal value of (0x9003) the EXIF tag for DateTimeOriginal
## For more information see: http://owl.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
#####################################################################################################
## History:
## - v1.0 - First release, retrieves all the data and stacks it somehow onto a FileInfo object
## - v2.0 - Refactor for clarity and PowerShell 2.0 features
#####################################################################################################
param(
[Parameter( ValueFromPipeLine = $true, ValueFromPipelineByPropertyname = $true, Mandatory = $true )]
[ValidateScript( { Test-Path -Path $_ -PathType Leaf } )]
[ValidatePattern('\.(jpg|tiff|bmp|png|gif)$')]
[Alias("PSPath")]
[string]$File
)
begin {
$null = [Reflection.Assembly]::LoadWithPartialName("PresentationCore");
function Get-ImageMetadata {
PARAM(
[Parameter(ValueFromPipeline=$true)]
[System.Windows.Media.Imaging.BitmapFrame]$bitmapFrame
,
[Parameter(ValueFromPipelineByPropertyName=$true)]
$Metadata
)
begin {
$ImageMetaData = @{}
}
process {
foreach($Meta in $Metadata) {
## To read metadata, you use GetQuery. To write metadata, you use SetQuery
## To WRITE metadata, you need a writer,
## but first you have to open the file ReadWrite, instead of Read only
# $writer = $bitmapFrame.CreateInPlaceBitmapMetadataWriter();
# if ($writer.TrySave()){
# $writer.SetQuery("/tEXt/{str=Description}", "Have a nice day.");
# } else {
# Write-Host "Couldn't save data" -Fore Red
# }
Write-Verbose "Getting metadata $Meta"
$next = $bitmapFrame.MetaData.GetQuery($Meta);
if($next.Location){
$next | ForEach-Object {
$ImageMetaData += Get-ImageMetadata $bitmapFrame "$($next.Location)$_"
}
} else {
# if($Meta.Split("/")[-1] -match "{ushort=(?<code>\d+)}") {
# # $path = "0x{0:X}" -f [int]$matches["code"]
# $Meta = [int]$matches["code"]
# }
Write-Verbose "Metadata $Meta = $Next"
$ImageMetaData.$Meta = $Next
}
}
}
end {
write-output $ImageMetaData
}
}
}
process {
$File = [string](Resolve-Path $File)
try {
$stream = new-object IO.FileStream $file, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read);
$decoder = [System.Windows.Media.Imaging.BitmapDecoder]::Create( $stream, "None", "Default" )
$ImageMetaData = $decoder.Frames[0] | Get-ImageMetadata
} catch {
Write-Error "WARNING: $_"
continue;
} finally {
$stream.Close()
$stream.Dispose()
}
$Output = New-Object IO.FileInfo $file
foreach($key in $ImageMetaData.Keys) {
Add-Member -in $Output -Type NoteProperty -Name $key -value $ImageMetaData.$key -Force
}
Write-Output $Output
}}
function Clear-ImageMetaData {
<#
.Synopsis
Modification of @Jaykuls function that writes (cleanes) images metadata.
.Description
Cleans meta data from file at $Path.
.Link
http://poshcode.org/617
.Example
Clear-ImageMetaData -Path c:\temp\test.jpg
Opens test.jpg, reads, cleans metadata and closes it.
.Example
ls *.jpg | Clear-ImageMetaData
Opens all .jpg files, and clears Meta Data for each one.
#>
[CmdletBinding()]
param (
[Parameter(
ValueFromPipeLine = $true,
ValueFromPipelineByPropertyname = $true,
Mandatory = $true
)]
[ValidateScript( { Test-Path -Path $_ -PathType Leaf } )]
[ValidatePattern('\.(jpg|tiff|bmp|png|gif)$')]
[string]$Path
)
process {
try {
$Path = [string](Resolve-Path $Path)
$stream = New-Object IO.FileStream $Path, 'Open', 'ReadWrite', 'ReadWrite'
$decoder = [System.Windows.Media.Imaging.BitmapDecoder]::Create( $stream, "PreservePixelFormat", "Default" )
$bitmapFrame = $decoder.Frames[0]
foreach($meta in $bitmapFrame.MetaData) {
$next = $bitmapFrame.MetaData.GetQuery($meta);
if($next.Location){
$next | ForEach-Object {
Get-ImageMetadata $bitmapFrame "$($next.Location)$_"
}
} else {
if($path.Split("/")[-1] -match "{ushort=(?<code>\d+)}") {
# $path = "0x{0:X}" -f [int]$matches["code"]
$path = [int]$matches["code"]
}
Add-Member -in ($Global:ImageMetaData) -Type NoteProperty -Name $path -value $next -Force
}
$writer = $bitmapFrame.CreateInPlaceBitmapMetadataWriter()
$Script = {
param ($path)
if($Writer.TrySave()) {
foreach ($Element in $path) {
$writer.SetQuery($Element,'')
& $Script $Element
}
} else {
Write-Error "Can't write metadata to $Path"
}
}
& $script $Writer
$Stream.Flush()
$Stream.Close()
$Stream.Dispose()
} catch {
Write-Verbose $_
}
}
} # END function Clear-ImageMetaData