3

I'm trying to resize an image in PowerShell without saving a temporary file and then save it to Active Directory.

I'm getting a Byte Array from a database (I have no control over what is sent to me) and I'm able to save this as a file easily like this:

[System.Io.File]::WriteAllBytes("C:\PathToFile\img.jpg", $PhotoArray)

What I need to do is resize the image and then update the thumbnail image in Active Directory. I'm able to do this with the original file as it's already given to me as a Byte Array like this:

Set-ADUser -Identity $UserName -Replace @{thumbnailPhoto=$Photo} -Server $AdServerName

I can resize the image to make it smaller using this code:

$Photo_MemoryStream = new-object System.IO.MemoryStream(,$PhotoAsByteArray)
$quality = 75
$bmp = [system.drawing.Image]::FromStream($Photo_MemoryStream)
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[decimal]$canvasWidth = 100.0
[decimal]$canvasHeight = 100.0

$myEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($myEncoder, $quality)
$myImageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|where {$_.MimeType -eq 'image/jpeg'}

$ratioX = $canvasWidth / $bmp.Width;
$ratioY = $canvasHeight / $bmp.Height;
$ratio = $ratioY
if($ratioX -le $ratioY){
  $ratio = $ratioX
}

$newWidth = [int] ($bmp.Width*$ratio)
$newHeight = [int] ($bmp.Height*$ratio)
$bmpResized = New-Object System.Drawing.Bitmap($newWidth, $newHeight)

$graph = [System.Drawing.Graphics]::FromImage($bmpResized)
$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($bmp,0,0 , $newWidth, $newHeight)

$bmpResized.Save("C:\PathToFile\img.jpg",$myImageCodecInfo, $($encoderParams))

How do I convert $bmpResized into a Byte Array so I can insert it into Active Directory? I'm sure this should be easy, but I've spent a long time trying to work out how to convert it into a Byte Array and failed!

I'm hoping someone out there has the magic answer I'm looking for :)

Blind Trevor
  • 746
  • 2
  • 9
  • 28
  • 2
    `$Photo = [System.IO.File]::ReadAllBytes("C:\PathToFile\img.jpg")`. Also, don't forget to `$bmpResized.Dispose()` when done – Theo Dec 20 '21 at 15:36
  • Could also save resized to MemoryStream, see: https://stackoverflow.com/questions/7350679/convert-a-bitmap-into-a-byte-array – dugas Dec 20 '21 at 15:39

2 Answers2

4

I've done this exact thing in C#. It's really the same in PowerShell since you're using .NET classes to do it.

You'd still use .Save, but to a MemoryStream, then use MemoryStream.ToArray(), like this:

$stream = New-Object System.IO.MemoryStream
$bmpResized.Save($stream, [System.Drawing.Imaging.ImageFormat]::Jpeg)
$byteArray = $stream.ToArray()

This assumes you want all your images in JPEG format.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
3

@Theo already gave answer in OP for dealing with file. Below is an example of saving resized photo to MemoryStream:

See (C# example): Convert a bitmap into a byte array

try {
 $resizedStream = New-Object System.IO.MemoryStream
 $bmpResized.Save($resizedStream, ,$myImageCodecInfo, $encoderParams)
 $resizedPhotoByteArray = $resizedStream.ToArray()
}
finally {
 if ($null -ne $resizedStream) {
  $resizedStream.Dispose()
 }
}
dugas
  • 12,025
  • 3
  • 45
  • 51