RaymonS
RaymonS

Reputation: 3

"Out of memory" error when pulling metadata from picture files using Powershell

Using Powershell, what I am trying to accomplish is:

  1. Loop through a directory of image files (with no file extensions, btw)
  2. Extract height and width of each
  3. Copy only image files that have particular attributes to another directory

What I'm currently doing (irrelevant code excluded):

Get-ChildItem | ForEach-Object {
    $img = [System.Drawing.Image]::FromFile($_.FullName)
    $dimensions = "$($img.Width) x $($img.Height)"
    $size = $img.Length
    If ($dimensions -eq "1920 x 1080" -and $size -gt 100kb)
        {
        Copy-Item -Path $sourceDir\$img -Destination $destDir\$img.jpg > $null
        }
}

The error I receive:

Exception calling "FromFile" with "1" argument(s): "Out of memory."
At C:\blahblah
+     $img = [System.Drawing.Image]::FromFile($_.FullName)
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : OutOfMemoryException

From what I've been researching, the error comes from loading a large image file in memory. I've read that streaming is the better way to go, but I haven't found a way to make this work and have little experience with it.

I have tried substituting the second line with: $img = [System.Drawing.Image]::FromStream([System.IO.MemoryStream]$_.FullName) but it barks at me saying Cannot convert the "C:\blahblah" value of type "System.String" to type "System.IO.MemoryStream"

Upvotes: 0

Views: 1305

Answers (2)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174690

I've read that streaming is the better way to go, but I haven't found a way to make this work and have little experience with it.

try {
  # create filestream from file
  $Stream = New-Object System.IO.FileStream -ArgumentList $_.FullName,'Open'
  $Image  = [System.Drawing.Image]::FromStream($Stream)
  $dimensions = "$($Image.Width) x $($Image.Height)"
  if($dimensions -eq '1920 x 1080' -and $_.Length -gt 100kb)
  {
    # Copy-Item
  }
}
finally {
  $Image,$Stream |ForEach-Object {
    # Clean up
    $_.Dispose()
  }
}

Upvotes: 0

Eris
Eris

Reputation: 7638

Converting my comment to an answer:

From the docs:

If the file does not have a valid image format or if GDI+ does not support the pixel format of the file, this method throws an OutOfMemoryException exception.

Upvotes: 2

Related Questions