powershellsystem.drawing

How to save bitmap created using System.Drawing.Image back out to base64


I am trying to get a base64 image string into the system.drawing.image object (done) and then back out to base64 (not working), to include inline in an HTML e-mail, but am having difficulty.

The below (commented out lines) came from a website page on how to do what isn't working, but the first error relates to no arguments in the MemoryStream object creation, so I am wondering if this is a wholly wrong way of going about this. I am having problems finding any other websites that detail how to do this, especially in Powershell and not these objects native .NET.

Note: The rest of the code works to edit the image as intended, shown by outputting to a file instead ($NewBitmap.save(<filename>)).

What am I missing?

$ImageBytes = [Convert]::FromBase64String($AccountNameInputExamplePic)
$ImageBytesMemoryStream = New-Object IO.MemoryStream($ImageBytes, 0, $ImageBytes.Length)

$OldBitmap = [System.Drawing.Image]::FromStream($ImageBytesMemoryStream, $true)
#new-object System.Drawing.Bitmap $Source
$NewBitmap = new-object System.Drawing.Bitmap $OldBitmap.width,$OldBitmap.height
$g=[System.Drawing.Graphics]::FromImage($NewBitmap)
$g.clear([System.Drawing.Color]::White)
$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic 
$g.DrawImage($OldBitmap, 0, 0, $OldBitmap.width,$OldBitmap.height)
$font = new-object System.Drawing.Font "Segoe UI",13
$brushFg = [System.Drawing.Brushes]::Yellow         
$g.DrawString($($UserAndPasswordExpiry.sAMAccountName),$font,$brushFg,190,463) 
$g.Dispose() 

#$ImageBytesMemoryStream = New-Object IO.MemoryStream()

#$NewBitmap.save($ImageBytesMemoryStream, System.Drawing.Imaging.ImageFormat.ToString())

#$ImageBase64 = [Convert]::ToBase64String($ImageBytesMemoryStream)

Solution

  • You have a few typos in the last section of your code:

    1. New-Object IO.MemoryStream(), when using the New-Object command you don't need parentheses to invoke a specific constructor, ctor arguments are space delimited and in this case and the parentheses are causing one of the issues. Recommended way of creating a new object using the newer syntax:

      $ImageBytesMemoryStream = [System.IO.MemoryStream]::new()
      
    2. Second argument passed to .Save: System.Drawing.Imaging.ImageFormat.ToString() is a syntax error. The argument is expecting a ImageFormat property value, see the link to check which are available. I'll use Png for the example.

      $NewBitmap.Save($ImageBytesMemoryStream, [System.Drawing.Imaging.ImageFormat]::Png)
      
    3. You're trying to convert a memory stream object to base64 instead of its bytes, use .ToArray() to get the image bytes stored in it:

      [Convert]::ToBase64String($ImageBytesMemoryStream.ToArray())
      

    Summing up, this is how the last section of your code should look:

    $ImageBytesMemoryStream = [System.IO.MemoryStream]::new()
    $NewBitmap.save($ImageBytesMemoryStream, [System.Drawing.Imaging.ImageFormat]::Png)
    $ImageBase64 = [Convert]::ToBase64String($ImageBytesMemoryStream.ToArray())