2010-01-16 23 views
10

Bazıları çoğaltılan ~ 20000 jpg resmi var. Ne yazık ki, bazı dosyalar EXIF ​​meta verileriyle etiketlenmiştir, bu nedenle basit bir dosya karesi çoğaltılmış olanı tanımlayamaz.Dotnet ile bir jpg dosyasında yalnızca görüntü verisi nasıl oluşturulur?

Bunları işlemek için bir Powershell komut dosyası oluşturmaya çalışıyorum, ancak yalnızca bitmap verisini ayıklamanın bir yolunu bulamıyorum.

System.drawing.bitmap yalnızca bayt değil, bir bitmap nesnesini döndürebilir. Bir GetHash() işlevi var, ancak görünüşe göre tüm dosya üzerinde hareket eder.

Bu dosyaları EXIF ​​bilgilerinin dışarıda bırakılacağı şekilde nasıl alabilirim? Mümkünse dış bağımlılıkları önlemeyi tercih ederim.

cevap

8

Bu, bir PowerShell V2.0 gelişmiş işlev uygulamasıdır. Biraz uzun ama aynı resim üzerinde aynı meta kodu ve dosya boyutları ile aynı karekodu (bitmap piksellerinden oluşturulmuş) sağladığını doğruladım.

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() } 
      } 
     } 
    } 
} 
4

Bir System.Drawing.Image içine JPEG yüklemek ve kullanabilirsiniz Eğer

using (var image = Image.FromFile("a.jpg")) 
using (var output = new MemoryStream()) 
{ 
    image.Save(output, ImageFormat.Bmp); 
    return output.ToArray(); 
} 
+1

İlk yaklaşım çalışmıyor . Aynı görüntü için farklı farklı kodlar döndürür (farklı meta veriler). İkinci yaklaşım işe yarıyor ve PowerShell betiğinde herkesin farklı seviyelerde tam olarak ne yaptıklarını açıklıyor. :-) –

0

powershell diline çevriliyor olabilir bayt, bu alın GetHashCode yöntemi

using (var image = Image.FromFile("a.jpg")) 
    return image.GetHashCode(); 

almak için var -

[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
$provider = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider 

foreach ($location in $args) 
{ 
    $files=get-childitem $location | where{$_.Extension -match "jpg|jpeg"} 
    foreach ($f in $files) 
     { 
     $bitmap = New-Object -TypeName System.Drawing.Bitmap -ArgumentList $f.FullName 
     $stream = New-Object -TypeName System.IO.MemoryStream 
     $bitmap.Save($stream) 

     $hashbytes = $provider.ComputeHash($stream.ToArray()) 
     $hashstring = "" 
     foreach ($byte in $hashbytes) 
      {$hashstring += $byte.tostring("x2")} 
     $f.FullName 
     $hashstring 
     echo "" 
     } 
} 

Bu, girdi dosyasına bakmaksızın aynı karmayı üretir, bu nedenle bir şey hala q değil Doğru yaz.

5

Burada çıkarılan kullanarak LockBits olarak görüntünün sadece bayt bir SHA256 karma üreten bir powershell komut dosyası: Bu aynı zamanda joker karakterler ve edebi yolları kabul eden bir boru hattı yetenekli versiyonudur. Bu, farklı her dosya için benzersiz bir karma üretmelidir. Dosyayı yinelenen kodu eklemediğimi lütfen unutmayın, ancak şu andaki hardcode c: \ test.bmp dosyasını foreach dizin yineleyici ile değiştirmek nispeten basit bir görev olmalıdır. $ Final değişkeni, final hashının hex - ascii dizesini içerir.

[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("-", ""); 

Belki eşdeğer C# kodu da anlayış ve size yardımcı olacak:

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("-", "");     
    } 
} 
+0

BitConverter.ToString() - güzel! –

0

Bu memorystream kaydetmek için daha hızlı bir yöntemdir:

$ms = New-Object System.IO.MemoryStream 
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Bmp) 
[void]$ms.Seek(0,'Begin') 
İlgili konular