A VB class for EXIF picture properties - and using it from Powershell.

I have been carrying on with my project to make EXIF data available in PowerShell.

When I searched for Powershell and EXIF it turned up this Blog post of Scott Hanselman's. He talks about a "nice little photo library" that extracts and interprets EXIF data from images, but when I tried to get hold of copy the link was dead, so I thought "How hard can it be ?" and looked the example in the VB Express's help. The answer was "Not very hard", and I built a class library I built goes like this.

 Public Class ExifImage
' Declare Constants, variables, subs and functions 
' - use PUBLIC to make them available to things which use the class. 
  Public BitMap As System.Drawing.Bitmap  ' I have lots of constants and a couple of functions to process information - just one shown here
  Public Const ExifIDDateTimeTaken As Integer = 36867 
 ' NEW is invoked when an item of this class is instantiated. Here I want to get a BITMAP object 
  Public Sub New(ByVal s As String)
     Me.BitMap = New System.Drawing.Bitmap(s)
  End Sub ' Now declare code to return properties. I don't want to write properties, so I declare them read only
  ReadOnly Property DateTimeTaken() As String
    Get
      DateTimeTaken = {what ever code you need}
    End Get
   End Property
 End class

This probably the time to say that it should be possible to create a new class which inherits everything from an existing class but System.Drawing.Bitmap doesn't allow this. So I just created a new object which contained a system.drawing.bitmap object - and made it accessible for other code which wanted to do anything beyond providing access to the 40 or so properties I wanted.. Those 40 properties meant quite a lot of code, but it was very repetitive stuff: even where I needed long SELECT ... CASE constructs to output "Flash switched on, but did not fire" or whatever for each of 20 different numbers values, it was mostly cutting and pasting. Parsing the maker note field to get Pentax specific information took a bit more work. Having compiled my code it was simply a case of loading it with  

 [reflection.assembly]::loadfile("C:\...longpath...\OneImage.dll") 

Now I can do something like this to get an image with my exif properties,

 $foo = New-Object oneimage.exifimage -argumentlist "I:\DCIM\100PENTX\IMGP3797.JPG" 

The [Tab] Key will expand $foo's properties so I can do this

 PS C:\Users\Jamesone\Pictures> $foo.Flash 
Flash off

That post of Scott's talks about "spot-welding" new properties on to existing objects. Not object inheritance, mind you, "super-gluing." Like it or hate it, like super-glue, you have to respect that it solves problems.  I copied his XML wholesale replaced his type name with mine and loaded it with

 Update-TypeData My.Types.PS1XML

Which let me get a directory with the DatePhotoTaken field. I got a bit more adventurous and build a different XML file which would show me bytes per pixel - a quick way to find out which files have been heavily compressed and which haven't

 <Types>
     <Type>
        <Name>System.IO.FileInfo</Name>
        <Members>
           <ScriptProperty>
                <Name>BytesPerPixel</Name>
                <GetScriptBlock>
                if ($this.Extension -match "jpg|raw")
                 {
                  $photo = new-object oneimage.exifimage $this.FullName
                  $this.length / ($photo.Height * $photo.width)
                }
                </GetScriptBlock>
            </ScriptProperty>
          </Members>
     </Type>
</Types>

I've attached the VB code and DLL so you can experiment. Disclaimer . Like any code on my blog, this code is provided as an Example for illustration purposes is only. It comes with No support and No warranty that it is fit for any purpose whatsoever.
Update - the code has been revised, and the link below has changed

Technorati tags: EXIF, Powershell, Windows, Photography

https://blogs.technet.com/jamesone/attachment/2767612.ashx