JSa*_*der 10 .net powershell jpeg image
我有~20000 jpg图像,其中一些是重复的.遗憾的是,某些文件已使用EXIF元数据标记,因此简单的文件哈希无法识别重复的文件.
我试图创建一个Powershell脚本来处理这些,但却找不到只提取位图数据的方法.
system.drawing.bitmap只能返回一个位图对象,而不是字节.有一个GetHash()函数,但它显然作用于整个文件.
如何以排除EXIF信息的方式散列这些文件?如果可能的话,我宁愿避免外部依赖.
这是PowerShell V2.0高级功能实现.它有点长,但我已经验证它在同一张图片上提供了相同的哈希码(从位图像素生成),但具有不同的元数据和文件大小.这是一个支持管道的版本,它也接受通配符和文字路径:
function Get-BitmapHashCode
{
[CmdletBinding(DefaultParameterSetName="Path")]
param(
[Parameter(Mandatory=$true,
Position=0,
ParameterSetName="Path",
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
HelpMessage="Path to bitmap file")]
[ValidateNotNullOrEmpty()]
[string[]]
$Path,
[Alias("PSPath")]
[Parameter(Mandatory=$true,
Position=0,
ParameterSetName="LiteralPath",
ValueFromPipelineByPropertyName=$true,
HelpMessage="Path to bitmap file")]
[ValidateNotNullOrEmpty()]
[string[]]
$LiteralPath
)
Begin {
Add-Type -AssemblyName System.Drawing
$sha = new-object System.Security.Cryptography.SHA256Managed
}
Process {
if ($psCmdlet.ParameterSetName -eq "Path")
{
# In -Path case we may need to resolve a wildcarded path
$resolvedPaths = @($Path | Resolve-Path | Convert-Path)
}
else
{
# Must be -LiteralPath
$resolvedPaths = @($LiteralPath | Convert-Path)
}
# Find PInvoke info for each specified path
foreach ($rpath in $resolvedPaths)
{
Write-Verbose "Processing $rpath"
try {
$bmp = new-object System.Drawing.Bitmap $rpath
$stream = new-object System.IO.MemoryStream
$writer = new-object System.IO.BinaryWriter $stream
for ($w = 0; $w -lt $bmp.Width; $w++) {
for ($h = 0; $h -lt $bmp.Height; $h++) {
$pixel = $bmp.GetPixel($w,$h)
$writer.Write($pixel.ToArgb())
}
}
$writer.Flush()
[void]$stream.Seek(0,'Begin')
$hash = $sha.ComputeHash($stream)
[BitConverter]::ToString($hash) -replace '-',''
}
finally {
if ($bmp) { $bmp.Dispose() }
if ($writer) { $writer.Close() }
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以将 JPEG 加载到 System.Drawing.Image 中并使用它的 GetHashCode 方法
using (var image = Image.FromFile("a.jpg"))
return image.GetHashCode();
Run Code Online (Sandbox Code Playgroud)
要获取字节,您可以
using (var image = Image.FromFile("a.jpg"))
using (var output = new MemoryStream())
{
image.Save(output, ImageFormat.Bmp);
return output.ToArray();
}
Run Code Online (Sandbox Code Playgroud)
小智 5
这是一个powershell脚本,它仅使用LockBits提取的图像字节生成SHA256哈希.这应该为每个不同的文件生成唯一的哈希.请注意,我没有包含文件迭代代码,但是使用foreach目录迭代器替换当前硬编码c:\ test.bmp应该是一个相对简单的任务.变量$ final包含最终哈希的十六进制 - ascii字符串.
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing.Imaging")
[System.Reflection.Assembly]::LoadWithPartialName("System.Security")
$bmp = [System.Drawing.Bitmap]::FromFile("c:\\test.bmp")
$rect = [System.Drawing.Rectangle]::FromLTRB(0, 0, $bmp.width, $bmp.height)
$lockmode = [System.Drawing.Imaging.ImageLockMode]::ReadOnly
$bmpData = $bmp.LockBits($rect, $lockmode, $bmp.PixelFormat);
$dataPointer = $bmpData.Scan0;
$totalBytes = $bmpData.Stride * $bmp.Height;
$values = New-Object byte[] $totalBytes
[System.Runtime.InteropServices.Marshal]::Copy($dataPointer, $values, 0, $totalBytes);
$bmp.UnlockBits($bmpData);
$sha = new-object System.Security.Cryptography.SHA256Managed
$hash = $sha.ComputeHash($values);
$final = [System.BitConverter]::ToString($hash).Replace("-", "");
Run Code Online (Sandbox Code Playgroud)
也许等效的C#代码也可以帮助您理解:
private static String ImageDataHash(FileInfo imgFile)
{
using (Bitmap bmp = (Bitmap)Bitmap.FromFile(imgFile.FullName))
{
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
IntPtr dataPointer = bmpData.Scan0;
int totalBytes = bmpData.Stride * bmp.Height;
byte[] values = new byte[totalBytes];
System.Runtime.InteropServices.Marshal.Copy(dataPointer, values, 0, totalBytes);
bmp.UnlockBits(bmpData);
SHA256 sha = new SHA256Managed();
byte[] hash = sha.ComputeHash(values);
return BitConverter.ToString(hash).Replace("-", "");
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4057 次 |
| 最近记录: |