header1   header
header
header Register : : Login header
header
connector   connector
menuleft menuright
submenu   submenu
left
Capturing Image Attributes
Last Post 11 Mar 2010 12:49 PM by PoSherLife. 8 Replies.
Printer Friendly
  •  
  •  
  •  
  •  
  •  
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages Not Resolved
JSUser is Offline
New Member
New Member
Posts:4
Avatar

--
10 Mar 2010 07:52 AM
    I am super new to powershell and I am currently trying to capture image attributes using the below script:

    [reflection.assembly]::loadfile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll") "Name|SizeInBytes|Width|Height" >> C:\JPGInfo.txt
    $filepath="C:\Images\"
    $imageFiles = gci -recurse C:\Images\ -include *.jpg
    foreach ($image in $imageFiles) {
    (gci $image).Name+"|"+(gci $image).Length+"|"+(New-Object -TypeName system.drawing.bitmap $image).Width+"|"+(New-Object -TypeName system.drawing.bitmap $image).Height >> C:\JPGInfo.txt
    }

    But I am getting errors similar to:

    Cannot convert argument "0", with value: "C:\Images\Blah.jpg", for "Bitmap" to type "System.Drawing.Image": "Cannot convert the  "C:\Images\Blah.jpg" value to type "System.IO.FileInfo" to type "System.Drawing.Image"."

    CategoryInfo:  InvalidOperation : (:) [New-Object], MethodException
    FullyQualifiedErrorID: ConstructorInvoikedThrowException, Microsoft.PowerShell.Commands.NewObjectCommand

    Any help would be appreciated.

    JS
    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    10 Mar 2010 08:14 AM
    Try this:

    function _Get-ImageStream
    {
    param ($File)

    $image = [System.Drawing.Image]::FromFile($File)
    $imageStream = New-Object System.IO.MemoryStream
    $image.Save($imageStream, [System.Drawing.Imaging.ImageFormat]::Jpeg)

    return $imageStream
    }


    [System.Reflection.Assembly]::LoadFile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")

    "Name|SizeInBytes|Width|Height" >> C:\JPGInfo.txt

    $path = "C:\Images\"
    $imageFiles = Get-ChildItem -Recurse $path -Include *.jpg

    foreach ($image in $imageFiles)
    {
    $image.Name + "|" + $image.Length + "|" + (_Get-ImageStream -File $image).Width + "|" + (_Get-ImageStream -File $image).Height >> C:\JPGInfo.txt
    }
    JSUser is Offline
    New Member
    New Member
    Posts:4
    Avatar

    --
    10 Mar 2010 09:40 AM
    Wow, thank you for the timely reply. I tried this script and it only outputs the image name and the file size while leaving Width & Length blank. The errors are gone, is there something else I am missing?

    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    10 Mar 2010 10:03 AM
    Hmmm, I think that was my bad. I forgot the .FullName property for the image. Try this:

    function _Get-ImageStream
    {
    param ($File)

    $image = [System.Drawing.Image]::FromFile($File)
    $imageStream = New-Object System.IO.MemoryStream
    $image.Save($imageStream, [System.Drawing.Imaging.ImageFormat]::Jpeg)

    return $imageStream
    }

    [System.Reflection.Assembly]::LoadFile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")

    "Name|SizeInBytes|Width|Height" >> C:\JPGInfo.txt

    $path = "C:\Images\"
    $imageFiles = Get-ChildItem -Recurse $path -Include *.jpg

    foreach ($image in $imageFiles)
    {
    $name = $image.Name
    $length = $image.Length
    $imageStream = _Get-ImageStream -File $image.FullName
    $width = $imagestream.Width
    $height = $imageStream.Height

    "$name|$length|$width|$height" >> C:\JPGInfo.txt
    }
    JSUser is Offline
    New Member
    New Member
    Posts:4
    Avatar

    --
    10 Mar 2010 11:27 AM
    The output is still the same. (Name|Size||) The script runs for 3-4 seconds on 16 jpgs so I know that the script is running against those images, I am just not sure why those attributes are not being output.
    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    10 Mar 2010 11:53 AM
    Ugh, sorry. Change "return $imageStream" to "return $image". That's why it wasn't working.

    function _Get-ImageStream
    {
    param ($File)

    $image = [System.Drawing.Image]::FromFile($File)
    $imageStream = New-Object System.IO.MemoryStream
    $image.Save($imageStream, [System.Drawing.Imaging.ImageFormat]::Jpeg)

    return $image
    }

    [System.Reflection.Assembly]::LoadFile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")

    "Name|SizeInBytes|Width|Height" >> C:\JPGInfo.txt

    $path = "C:\Images\"
    $imageFiles = Get-ChildItem -Recurse $path -Include *.jpg

    foreach ($image in $imageFiles)
    {
    $name = $image.Name
    $length = $image.Length
    $imageStream = _Get-ImageStream -File $image.FullName
    $width = $imagestream.Width
    $height = $imageStream.Height

    "$name|$length|$width|$height" >> C:\JPGInfo.txt
    }
    JSUser is Offline
    New Member
    New Member
    Posts:4
    Avatar

    --
    11 Mar 2010 07:58 AM
    This works perfectly. Unfortunately, I am trying to get these attributes for over 1.5M images and I am running into a memory issue around 20k images. Is there any way to dispose objects held in memory for this?
    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    11 Mar 2010 08:20 AM
    Yes, there is. In hindsight, I've realized the script can be simplified to this also:

    [System.Reflection.Assembly]::LoadFile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")

    "Name|SizeInBytes|Width|Height" >> C:\JPGInfo.txt

    $path = "C:\Images\"
    $images = Get-ChildItem -Recurse $path -Include *.jpg

    foreach ($image in $images)
    {
    $name = $image.Name
    $length = $image.Length
    $imageFile = [System.Drawing.Image]::FromFile($image.FullName)
    $width = $imageFile.Width
    $height = $imageFile.Height

    "$name|$length|$width|$height" >> C:\JPGInfo.txt

    $imageFile.Dispose()
    }
    PoSherLifeUser is Offline
    Basic Member
    Basic Member
    Posts:364
    Avatar

    --
    11 Mar 2010 12:49 PM
    Just a few things:

    Why the output to a txt file?  If a CSV will work this is a more efficient way to do it.  It gives the ability to more effectively save the data as an object, then only write to disk 1x.

    When you load an assembly using [void] will keep the console output cleaner.

    Instead of creating several object, just create a single object with multiple properties.  I'm sure this is a VERY fast script already, but its just a good practice to keep everything tidy and quick.
    ========================================
    [Void][System.Reflection.Assembly]::LoadFile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")

    $path = "C:\Images\"

    $data = Get-ChildItem -Recurse $path -Include *.jpg | % {
        $imageFile = [System.Drawing.Image]::FromFile($_.FullName) ;
        New-Object PSObject -Property @{
            name = $_.Name
            length = $_.Length
            width = $imageFile.Width
            height = $imageFile.Height
        }
    }
    $data | Export-Csv C:\JPGInfo.csv -NoTypeInformation
    When at first you don't succeed Step-Into

    http://theposherlife.blogspot.com
    http://www.jandctravels.com

    You are not authorized to post a reply.


    Active Forums 4.3
    right
    footer   footer
    footer Sponsored by Quest Software • SAPIEN Technologies • Compellent • Microsoft Windows Server 2008 R2 footer
    footer   footer