2017-02-10 20 views
1

Я нашел метод C# в this SO answer, чтобы определить, имеет ли изображение прозрачность. Я пытаюсь преобразовать метод в PowerShell.InteropServices.Marshal.Copy всегда равен нулю в скрипте PowerShell, преобразованном из метода C#

К сожалению, я не могу заставить его работать. Кажется, что все работает нормально до части маршала. Копия, и все значения заполняются должным образом, за исключением массива Bytes, который заполнен нулями даже после Marshal.Copy.

Ниже приводится исходный код в C#:

public bool IsAlphaBitmap(ref System.Drawing.Imaging.BitmapData BmpData) 
{ 
    byte[] Bytes = new byte[BmpData.Height * BmpData.Stride]; 
    Marshal.Copy(BmpData.Scan0, Bytes, 0, Bytes.Length); 
    for (p = 3; p < Bytes.Length; p += 4) { 
     if (Bytes[p] != 255) return true; 
    } 
    return false; 
} 

И это версия PowerShell я до сих пор (это не работает):

function IsAlphaBitMap([string]$imagepath) 
{ 
    $BitMap = New-Object System.Drawing.BitMap($imagepath) 
    $Rect = New-Object System.Drawing.Rectangle(0, 0, $BitMap.Width, $BitMap.Height) 
    $BmpData = [System.Drawing.Imaging.BitmapData]$BitMap.LockBits($Rect, [System.Drawing.Imaging.ImageLockMode]::ReadWrite, $BitMap.PixelFormat) 

    $Bytes = New-Object byte[] ($BmpData.Height * $BmpData.Stride) 
    [System.Runtime.InteropServices.Marshal]::Copy($BmpData.Scan0, $Bytes, 0, $Bytes.Length) 
    for($p=3 ; $p -lt $Bytes.Length ; $p+=4) 
    { 
     if ($Bytes[$p] -ne 255) { write-host $Bytes[$p] } # { return $true } 
    } 
    return $false 
} 

я использовать write-host в цикл, а не возвращаемое значение, так что я могу читать вывод каждой итерации, которая всегда равна нулю. Может ли кто-нибудь увидеть, где я ошибся?

+0

Вы можете рассмотреть возможность добавления вывода из 'write-host', даже если этот вывод представляет собой строки с нулями. Кроме того, вы прислушались к предупреждению в одном из комментариев, где говорится: «Это работает только для 32 изображений в формате bpp»? Если вы это сделали, вы должны сказать, что вы проводили тесты с использованием таких изображений. – Sabuncu

+0

Извините, я не прояснил это. Вы правы, я только планировал запустить это на 32-битных изображениях RGBA PNG. Для PNG типа 0, 2 и 3 я проверяю фрагмент tRNS и тип 4, я проверяю с ImageMagick (это медленно!), Но редко в моем случае, так что все в порядке. Я надеялся, что это будет быстрее, чем использование ImageMagick, но мне еще нужно заставить его работать. – Bighead

ответ

1

Ваш код работает для меня как есть (PS5.1 на Win7), но у него есть проблемы. Некоторые фотографии не имеют альфа-канала, поэтому каждый пиксель состоит только из байтов изображения, без альфы. Количество байтов также различается в зависимости от формата: менее одного, 1, 2, 3, 4, 6, 8 байтов.

Проверить PixelFormat как флаг битовой маски:

$BitMap = [Drawing.BitMap]$imagepath 
if ($BitMap.PixelFormat.value__ -band [Drawing.Imaging.PixelFormat]::Alpha -eq 0) { 
    return $false 
} 

И использовать фактическую длину пикселя:

$pixelBytes = [Drawing.Image]::GetPixelFormatSize($bitmap.PixelFormat) -shr 3 
if (!$pixelBytes) { 
    Write-Warning 'Sorry, 2lazy2support paletted images with pixels less than 8 bits' 
    return $null 
} 

$len = $Bytes.Length 
for ($p = $pixelBytes - 1; $p -lt $len; $p += $pixelBytes) { 
    if ($Bytes[$p] -ne 255) { 
     return $true 
    } 
} 
+0

Благодарим вас за предложение, это чрезвычайно полезно и расширило мою первоначальную цель для этой функции. – Bighead

0

Спасибо за предложения, теперь я могу использовать его для других изображений, как хорошо! И это, наконец, работает сейчас как-то! Вот полная рабочая функция + предложения wOxxOm в случае, если кто-то наткнется на нее в поиске Google. Я знаю, что много раз за последние годы я искал ответы, это отличный сайт с великими людьми.

function IsAlphaBitMap([string]$imagepath) 
{ 
    $BitMap = [Drawing.BitMap]$imagepath 
    if (($BitMap.PixelFormat.value__ -band [Drawing.Imaging.PixelFormat]::Alpha) -eq 0) 
    { 
     return $false 
    } 
    $pixelBytes = [Drawing.Image]::GetPixelFormatSize($BitMap.PixelFormat) -shr 3 
    if (!$pixelBytes) 
    { 
     Write-Warning 'Sorry, 2lazy2support paletted images with pixels less than 8 bits' 
     return $null 
    } 
    $Rect = New-Object System.Drawing.Rectangle(0, 0, $BitMap.Width, $BitMap.Height) 
    $BmpData = [Drawing.Imaging.BitmapData]$BitMap.LockBits($Rect, [System.Drawing.Imaging.ImageLockMode]::ReadWrite, $BitMap.PixelFormat) 
    $Bytes = New-Object byte[] ($BmpData.Height * $BmpData.Stride) 
    [System.Runtime.InteropServices.Marshal]::Copy($BmpData.Scan0, $Bytes, 0, $Bytes.Length) 
    $BitMap.Dispose() 

    $len = $Bytes.Length 
    for($p = ($pixelBytes - 1) ; $p -lt $len ; $p += $pixelBytes) 
    { 
     if ($Bytes[$p] -ne 255) 
     { 
      return $true 
     } 
    } 
    return $false 
} 

Отредактировано потому, что я забыл убрать растровое изображение, которое впоследствии вызвало проблемы.