I thought I’d look at another approach to retrieving information about images. Previously, I demonstrated how one can get file properties (including images) by using plain VBA or PowerShell:

Today, however, I thought I’d demonstrate using the GDI Plus API. This will be Part 1 in a series of posts on the GDI Plus API. It is a very complex and versatile API, so I am breaking it up into digestible pieces of information.
The GDI Plus API
The GDI Plus API can do much, much more than retrieving information about an image! It can for instance, edit an image (watermark anyone?!), you can even use it to alter applications, dialogs, … This is why it is more complex to use, because it is very complex!
I won’t bore you with tons of talk, here’s the code!
Simply create a new Standard Module and Copy/Paste the following
Option Explicit
'API Declarations, ENUMS, TYPES, Global Variables, ...
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'GDI - General
Private Declare Function GdiplusStartup Lib "gdiplus" (ByRef token As Long, ByRef lpInput As GDIPlusStartupInput, Optional ByRef lpOutput As Any) As Status
Private Declare Function GdiplusShutdown Lib "gdiplus" (ByVal token As Long) As Status
Private Declare Function GdipCreateBitmapFromFile Lib "gdiplus" (ByVal FileName As Long, ByRef Bitmap As Long) As Status
Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal image As Long) As Status
'GDI - Image / Properties
Private Declare Function GdipGetPropertyItemSize Lib "gdiplus" (ByVal image As Long, ByVal propId As Long, ByRef Size As Long) As Status
Private Declare Function GdipGetPropertyItem Lib "gdiplus" (ByVal image As Long, ByVal propId As Long, ByVal PropSize As Long, ByRef buffer As Any) As Status
'Helper API Declarations
Private Declare Function lstrlenW Lib "kernel32" (lpString As Any) As Long
Private Declare Function lstrcpyW Lib "kernel32" (lpString1 As Any, lpString2 As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Const GdiPlusVersion As Long = 1
Private Type GDIPlusStartupInput
GdiPlusVersion As Long
DebugEventCallback As Long
SuppressBackgroundThread As Long
SuppressExternalCodecs As Long
End Type
Private Type PropertyItem
id As Long 'PropertyTagId
Length As Long
Type As Integer 'PropertyTagType
Value As Long
End Type
'GDI+ Status Constants
Private Enum Status
'https://docs.microsoft.com/en-us/windows/win32/api/gdiplustypes/ne-gdiplustypes-status
OK = 0
GenericError = 1
InvalidParameter = 2
OutOfMemory = 3
ObjectBusy = 4
InsufficientBuffer = 5
NotImplemented = 6
Win32Error = 7
WrongState = 8
Aborted = 9
FileNotFound = 10
ValueOverflow = 11
AccessDenied = 12
UnknownImageFormat = 13
FontFamilyNotFound = 14
FontStyleNotFound = 15
NotTrueTypeFont = 16
UnsupportedGdiplusVersion = 17
GdiplusNotInitialized = 18
PropertyNotFound = 19
PropertyNotSupported = 20
ProfileNotFound = 21
End Enum
Private Enum PropertyTagType
'https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-image-property-tag-type-constants
TypeByte = 1
TypeASCII = 2
TypeShort = 3
TypeLong = 4
TypeRational = 5
TypeUndefined = 7
TypeSLong = 9
TypeSRational = 10
End Enum
'Image Property Tag Constants
Public Enum PropertyTagId
'https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-property-tags-in-alphabetical-order
'https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-property-tags-in-numerical-order
' 0x0... => &H...
' https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-property-item-descriptions
GpsVer = 0 '&H0&
GpsLatitudeRef = 1 '&H1&
GpsLatitude = 2 '&H2&
GpsLongitudeRef = 3 '&H3&
GpsLongitude = 4 '&H4&
GpsAltitudeRef = 5 '&H5&
GpsAltitude = 6 '&H6&
GpsGpsTime = 7 '&H7&
GpsGpsSatellites = 8 '&H8&
GpsGpsStatus = 9 '&H9&
GpsGpsMeasureMode = 10 '&HA&
GpsGpsDop = 11 '&HB&
GpsSpeedRef = 12 '&HC&
GpsSpeed = 13 '&HD&
GpsTrackRef = 14 '&HE&
GpsTrack = 15 '&HF&
GpsImgDirRef = 16 '&H10&
GpsImgDir = 17 '&H11&
GpsMapDatum = 18 '&H12&
GpsDestLatRef = 19 '&H13&
GpsDestLat = 20 '&H14&
GpsDestLongRef = 21 '&H15&
GpsDestLong = 22 '&H16
GpsDestBearRef = 23 '&H17&
GpsDestBear = 24 '&H18&
GpsDestDistRef = 25 '&H19&
GpsDestDist = 26 '&H1A&
NewSubfileType = 254 '&HFE&
SubfileType = 255 '&HFF&
ImageWidth = 256 '&H100&
ImageHeight = 257 '&H101&
BitsPerSample = 258 '&H102&
Compression = 259 '&H103&
PhotometricInterp = 262 '&H106&
ThreshHolding = 263 '&H107&
CellWidth = 264 '&H108&
CellHeight = 265 '&H109&
FillOrder = 266 '&H10A&
DocumentName = 269 '&H10D&
ImageDescription = 270 '&H10E&
EquipMake = 271 '&H10F&
EquipModel = 272 '&H110&
StripOffsets = 273 '&H111&
Orientation = 274 '&H112&
SamplesPerPixel = 277 '&H115&
RowsPerStrip = 278 '&H116&
StripBytesCount = 279 '&H117&
MinSampleValue = 280 '&H118&
MaxSampleValue = 281 '&H119&
XResolution = 282 '&H11A&
YResolution = 283 '&H11B&
PlanarConfig = 284 '&H11C&
PageName = 285 '&H11D&
XPosition = 286 '&H11E&
YPosition = 287 '&H11F&
FreeOffset = 288 '&H120&
FreeByteCounts = 289 '&H121&
GrayResponseUnit = 290 '&H122&
GrayResponseCurve = 291 '&H123&
T4Option = 292 '&H124&
T6Option = 293 '&H125&
ResolutionUnit = 296 '&H128&
PageNumber = 297 '&H129&
TransferFunction = 301 '&H12D&
SoftwareUsed = 305 '&H131&
DateTime = 306 '&H132&
Artist = 315 '&H13B&
HostComputer = 316 '&H13C&
Predictor = 317 '&H13D&
WhitePoint = 318 '&H13E&
PrimaryChromaticities = 319 '&H13F&
ColorMap = 320 '&H140&
HalftoneHints = 321 '&H141&
TileWidth = 322 '&H142&
TileLength = 323 '&H143&
TileOffset = 324 '&H144&
TileByteCounts = 325 '&H145&
InkSet = 332 '&H14C&
InkNames = 333 '&H14D&
NumberOfInks = 334 '&H14E&
DotRange = 336 '&H150&
TargetPrinter = 337 '&H151&
ExtraSamples = 338 '&H152&
SampleFormat = 339 '&H153&
TransferRange = 342 '&H156&
JPEGProc = 512 '&H200&
JPEGInterFormat = 513 '&H201&
JPEGInterLength = 514 '&H202&
JPEGRestartInterval = 515 '&H203&
JPEGLosslessPredictors = 517 '&H205&
JPEGPointTransforms = 518 '&H206&
JPEGQTables = 519 '&H207&
JPEGDCTables = 520 '&H208&
JPEGACTables = 521 '&H209&
YCbCrCoefficients = 529 '&H211&
YCbCrSubsampling = 530 '&H212&
YCbCrPositioning = 531 '&H213&
REFBlackWhite = 532 '&H214&
Gamma = 769 '&H301&
ICCProfileDescriptor = 770 '&H302&
SRGBRenderingIntent = 771 '&H303&
ImageTitle = 800 '&H320&
ResolutionXUnit = 20481 '&H5001&
ResolutionYUnit = 20482 '&H5002&
ResolutionXLengthUnit = 20483 '&H5003&
ResolutionYLengthUnit = 20484 '&H5004&
PrintFlags = 20485 '&H5005&
PrintFlagsVersion = 20486 '&H5006&
PrintFlagsCrop = 20487 '&H5007&
PrintFlagsBleedWidth = 20488 '&H5008&
PrintFlagsBleedWidthScale = 20489 '&H5009&
HalftoneLPI = 20490 '&H500A&
HalftoneLPIUnit = 20491 '&H500B&
HalftoneDegree = 20492 '&H500C&
HalftoneShape = 20493 '&H500D&
HalftoneMisc = 20494 '&H500E&
HalftoneScreen = 20495 '&H500F&
JPEGQuality = 20496 '&H5010&
GridSize = 20497 '&H5011&
ThumbnailFormat = 20498 '&H5012&
ThumbnailWidth = 20499 '&H5013&
ThumbnailHeight = 20500 '&H5014&
ThumbnailColorDepth = 20501 '&H5015&
ThumbnailPlanes = 20502 '&H5016&
ThumbnailRawBytes = 20503 '&H5017&
ThumbnailSize = 20504 '&H5018&
ThumbnailCompressedSize = 20505 '&H5019&
ColorTransferFunction = 20506 '&H501A&
ThumbnailData = 20507 '&H501B&
ThumbnailImageWidth = 20512 '&H5020&
ThumbnailImageHeight = 20513 '&H5021&
ThumbnailBitsPerSample = 20514 '&H5022&
ThumbnailCompression = 20515 '&H5023&
ThumbnailPhotometricInterp = 20516 '&H5024&
ThumbnailImageDescription = 20517 '&H5025&
ThumbnailEquipMake = 20518 '&H5026&
ThumbnailEquipModel = 20519 '&H5027&
ThumbnailStripOffsets = 20520 '&H5028&
ThumbnailOrientation = 20521 '&H5029&
ThumbnailSamplesPerPixel = 20522 '&H502A&
ThumbnailRowsPerStrip = 20523 '&H502B&
ThumbnailStripBytesCount = 20524 '&H502C&
ThumbnailResolutionX = 20525 '&H502D&
ThumbnailResolutionY = 20526 '&H502E&
ThumbnailPlanarConfig = 20527 '&H502F&
ThumbnailResolutionUnit = 20528 '&H5030&
ThumbnailTransferFunction = 20529 '&H5031&
ThumbnailSoftwareUsed = 20530 '&H5032&
ThumbnailDateTime = 20531 '&H5033&
ThumbnailArtist = 20532 '&H5034&
ThumbnailWhitePoint = 20533 '&H5035&
ThumbnailPrimaryChromaticities = 20534 '&H5036&
ThumbnailYCbCrCoefficients = 20535 '&H5037&
ThumbnailYCbCrSubsampling = 20536 '&H5038&
ThumbnailYCbCrPositioning = 20537 '&H5039&
ThumbnailRefBlackWhite = 20538 '&H503A&
ThumbnailCopyRight = 20539 '&H503B&
LuminanceTable = 20624 '&H5090&
ChrominanceTable = 20625 '&H5091&
FrameDelay = 20736 '&H5100&
LoopCount = 20737 '&H5101&
GlobalPalette = 20738 '&H5102&
IndexBackground = 20739 '&H5103&
IndexTransparent = 20740 '&H5104&
PixelUnit = 20752 '&H5110&
PixelPerUnitX = 20753 '&H5111&
PixelPerUnitY = 20754 '&H5112&
PaletteHistogram = 20755 '&H5113&
Copyright = 33432 '&H8298&
ExifExposureTime = 33434 '&H829A&
ExifFNumber = 33437 '&H829D&
ExifIFD = 34665 '&H8769&
ICCProfile = 34675 '&H8773&
ExifExposureProg = 34850 '&H8822&
ExifSpectralSense = 34852 '&H8824&
GpsIFD = 34853 '&H8825&
ExifISOSpeed = 34855 '&H8827&
ExifOECF = 34856 '&H8828&
ExifVer = 36864 '&H9000&
ExifDTOrig = 36867 '&H9003&
ExifDTDigitized = 36868 '&H9004&
ExifCompConfig = 37121 '&H9101&
ExifCompBPP = 37122 '&H9102&
ExifShutterSpeed = 37377 '&H9201&
ExifAperture = 37378 '&H9202&
ExifBrightness = 37379 '&H9203&
ExifExposureBias = 37380 '&H9204&
ExifMaxAperture = 37381 '&H9205&
ExifSubjectDist = 37382 '&H9206&
ExifMeteringMode = 37383 '&H9207&
ExifLightSource = 37384 '&H9208&
ExifFlash = 37385 '&H9209&
ExifFocalLength = 37386 '&H920A&
ExifMakerNote = 37500 '&H927C&
ExifUserComment = 37510 '&H9286&
ExifDTSubsec = 37520 '&H9290&
ExifDTOrigSS = 37521 '&H9291&
ExifDTDigSS = 37522 '&H9292&
ExifFPXVer = 40960 '&HA000&
ExifColorSpace = 40961 '&HA001&
ExifPixXDim = 40962 '&HA002&
ExifPixYDim = 40963 '&HA003&
ExifRelatedWav = 40964 '&HA004&
ExifInterop = 40965 '&HA005&
ExifFlashEnergy = 41483 '&HA20B&
ExifSpatialFR = 41484 '&HA20C&
ExifFocalXRes = 41486 '&HA20E&
ExifFocalYRes = 41487 '&HA20F&
ExifFocalResUnit = 41488 '&HA210&
ExifSubjectLoc = 41492 '&HA214&
ExifExposureIndex = 41493 '&HA215&
ExifSensingMethod = 41495 '&HA217&
ExifFileSource = 41728 '&HA300&
ExifSceneType = 41729 '&HA301&
ExifCfaPattern = 41730 '&HA302&
End Enum
Dim lGDIpToken As Long
Dim bGDIpInitialized As Boolean
Dim lBitmap As Long
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
Private Function GDIErrorToString(ByVal lGDIError As Status) As String
Select Case lGDIError
Case GenericError
GDIErrorToString = "Generic Error."
Case InvalidParameter
GDIErrorToString = "Invalid Parameter."
Case OutOfMemory
GDIErrorToString = "Out Of Memory."
Case ObjectBusy
GDIErrorToString = "Object Busy."
Case InsufficientBuffer
GDIErrorToString = "Insufficient Buffer."
Case NotImplemented
GDIErrorToString = "Not Implemented."
Case Win32Error
GDIErrorToString = "Win32 Error."
Case WrongState
GDIErrorToString = "Wrong State."
Case Aborted
GDIErrorToString = "Aborted."
Case FileNotFound
GDIErrorToString = "File Not Found."
Case ValueOverflow
GDIErrorToString = "Value Overflow."
Case AccessDenied
GDIErrorToString = "Access Denied."
Case UnknownImageFormat
GDIErrorToString = "Unknown Image Format."
Case FontFamilyNotFound
GDIErrorToString = "FontFamily Not Found."
Case FontStyleNotFound
GDIErrorToString = "FontStyle Not Found."
Case NotTrueTypeFont
GDIErrorToString = "Not TrueType Font."
Case UnsupportedGdiplusVersion
GDIErrorToString = "Unsupported Gdiplus Version."
Case GdiplusNotInitialized
GDIErrorToString = "Gdiplus Not Initialized."
Case PropertyNotFound
GDIErrorToString = "Property Not Found."
Case PropertyNotSupported
GDIErrorToString = "Property Not Supported."
Case Else
GDIErrorToString = "Unknown Error."
End Select
End Function
Private Function GetPropertyValue(ByVal PropertyItemLength As Long, ByVal PropertyItemValue As Long, ByVal lPropertyType As PropertyTagType) As String
Dim byteRetValue As Byte
Dim lRetValue As Long
Dim iRetValue As Integer
Dim bytProperty() As Byte
Dim sProperty As String
Dim DataLength As Long
Dim Numerator As Long
Dim Denominator As Long
Dim sTemp As String
Dim i As Long
If PropertyItemLength = 0 Then
GetPropertyValue = ""
Exit Function
End If
Select Case lPropertyType
Case PropertyTagType.TypeByte
DataLength = 1
ReDim bytProperty(PropertyItemLength - 1)
Call CopyMemory(bytProperty(0), ByVal PropertyItemValue, PropertyItemLength)
Call CopyMemory(byteRetValue, bytProperty(0), DataLength)
Erase bytProperty
GetPropertyValue = byteRetValue
Case PropertyTagType.TypeASCII
sProperty = Space$(lstrlenW(ByVal PropertyItemValue))
Call lstrcpyW(ByVal StrPtr(sProperty), ByVal PropertyItemValue)
GetPropertyValue = Trim$(Left$(StrConv(sProperty, vbUnicode), PropertyItemLength - 1))
Case PropertyTagType.TypeShort
DataLength = 2
ReDim bytProperty(PropertyItemLength - 1)
Call CopyMemory(bytProperty(0), ByVal PropertyItemValue, PropertyItemLength)
Call CopyMemory(iRetValue, bytProperty(0), DataLength)
Erase bytProperty
GetPropertyValue = iRetValue
Case PropertyTagType.TypeLong, PropertyTagType.TypeSLong
DataLength = 4
ReDim bytProperty(PropertyItemLength - 1)
Call CopyMemory(bytProperty(0), ByVal PropertyItemValue, PropertyItemLength)
Call CopyMemory(lRetValue, bytProperty(0), DataLength)
Erase bytProperty
GetPropertyValue = lRetValue
Case PropertyTagType.TypeRational, PropertyTagType.TypeSRational
DataLength = 8
ReDim bytProperty(PropertyItemLength - 1)
Call CopyMemory(bytProperty(0), ByVal PropertyItemValue, PropertyItemLength)
Call CopyMemory(Numerator, bytProperty(0), DataLength / 2)
Call CopyMemory(Denominator, bytProperty(0 + (DataLength / 2)), DataLength / 2)
Erase bytProperty
GetPropertyValue = CStr(Numerator) & "/" & CStr(Denominator)
GetPropertyValue = Eval(GetPropertyValue)
Case PropertyTagType.TypeUndefined
ReDim bytProperty(PropertyItemLength - 1)
Call CopyMemory(bytProperty(0), ByVal PropertyItemValue, PropertyItemLength)
For i = 1 To PropertyItemLength - 1
If i > 1 Then sProperty = sProperty & Chr$(32)
sTemp = Hex$(bytProperty(i - 1))
If Len(sTemp) = 1 Then sTemp = "0" & sTemp
sProperty = sProperty & sTemp
Next i
Erase bytProperty
GetPropertyValue = sProperty
End Select
End Function
'---------------------------------------------------------------------------------------
' Procedure : GetImageProperty
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Return the value of the specified property for a given image file
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFile : Fully qualified path and filename of the image file to get info about
' lProp : Property to retrieve the value of
'
' Usage:
' ~~~~~~
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", ImageHeight) => 3648
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", ImageWidth) => 2736
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", EquipModel) => ELE-L04
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", DateTime) => 2021:05:08 17:01:56
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", ExifISOSpeed) => 250
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", ExifShutterSpeed) => 29.8973
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", ExifAperture) => 1.69
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", XResolution) => 72
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", YResolution) => 72
'? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", SoftwareUsed) => ELE-L04 11.0.0.146(C792E5R1P3)
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2022-01-08 Initial Blog Release
'---------------------------------------------------------------------------------------
Public Function GetImageProperty(sFile As String, ByVal lProp As PropertyTagId)
On Error GoTo Error_Handler
Dim GDIpStartupInput As GDIPlusStartupInput
Dim GDIStatus As Status
Dim PI As PropertyItem
Dim propItemData() As Byte
Dim sOutput As String
Dim lPropItemSize As Long
Dim vLegibleValue As Variant
Const bDebug As Boolean = False 'Change to True for Development purposes/debugging
'Start GDI
'-------------------------------------------------------------------------------------
If bGDIpInitialized = False Then
GDIpStartupInput.GdiPlusVersion = 1
GDIStatus = GdiplusStartup(lGDIpToken, GDIpStartupInput, ByVal 0)
If GDIStatus <> Status.OK Then
MsgBox "Unable to start the GDI+ API" & vbCrLf & vbCrLf & GDIErrorToString(GDIStatus), vbCritical Or vbOKOnly, "Operation Aborted"
GoTo Error_Handler_Exit
Else
bGDIpInitialized = True
End If
End If
'Load our Image to work with
'-------------------------------------------------------------------------------------
'In case we already have something in memory let's dispose of it properly
If lBitmap <> 0 Then
GDIStatus = GdipDisposeImage(lBitmap)
If GDIStatus <> Status.OK Then
MsgBox "Unable to dispose of the current image in memory" & vbCrLf & vbCrLf & GDIErrorToString(GDIStatus), vbCritical Or vbOKOnly, "Operation Aborted"
GoTo Error_Handler_Exit
End If
End If
'Now let's proceed with loading the actual image we want to work with
GDIStatus = GdipCreateBitmapFromFile(StrPtr(sFile), lBitmap)
If GDIStatus <> Status.OK Then
MsgBox "Unable to load the specified image" & vbCrLf & vbCrLf & GDIErrorToString(GDIStatus), vbCritical Or vbOKOnly, "Operation Aborted"
GoTo Error_Handler_Exit
End If
'Work with the image
'-------------------------------------------------------------------------------------
If lBitmap Then
GDIStatus = GdipGetPropertyItemSize(lBitmap, lProp, lPropItemSize)
If GDIStatus <> Status.OK Then
' If GDIStatus = Status.PropertyNotFound Then
' GetImageProperty = "Not Defined"
' Else
MsgBox "Unable to get the specified property size" & vbCrLf & vbCrLf & GDIErrorToString(GDIStatus), vbCritical Or vbOKOnly, "Operation Aborted"
' End If
GoTo Error_Handler_Exit
End If
If (lPropItemSize > 0) Then
ReDim propItemData(lPropItemSize - 1)
GDIStatus = GdipGetPropertyItem(lBitmap, lProp, lPropItemSize, propItemData(0))
If GDIStatus <> Status.OK Then
MsgBox "Unable to get the specified property" & vbCrLf & vbCrLf & GDIErrorToString(GDIStatus), vbCritical Or vbOKOnly, "Operation Aborted"
GoTo Error_Handler_Exit
End If
Call CopyMemory(PI, propItemData(0), LenB(PI))
Erase propItemData
GetImageProperty = GetPropertyValue(PI.Length, PI.Value, PI.Type)
End If
End If
Error_Handler_Exit:
On Error Resume Next
'Shutdown GDI
'-------------------------------------------------------------------------------------
If bGDIpInitialized = True Then
If lBitmap <> 0 Then
GDIStatus = GdipDisposeImage(lBitmap)
If GDIStatus <> Status.OK Then
MsgBox "Unable to dispose of the processed image" & vbCrLf & vbCrLf & GDIErrorToString(GDIStatus), vbCritical Or vbOKOnly, "Operation Aborted"
Exit Function
Else
lBitmap = 0
End If
End If
GDIStatus = GdiplusShutdown(lGDIpToken)
If GDIStatus <> Status.OK Then
MsgBox "Unable to shutdown the GDI+ API" & vbCrLf & vbCrLf & GDIErrorToString(GDIStatus), vbCritical Or vbOKOnly, "Operation Aborted"
Exit Function
Else
bGDIpInitialized = False
End If
End If
Exit Function
Error_Handler:
MsgBox "The following error has occured" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: GetImageProperty" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
and as indicated in the comments, you need only call the GetImageProperty() function specifying the file to query and the property you are after to get the value back!
? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", ImageHeight)
Returns => 3648
? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", EquipModel)
Returns => ELE-L04
? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", DateTime)
Returns => 2021:05:08 17:01:56
? GetImageProperty("C:\Temp\IMG_20210508_170154.jpg", ExifISOSpeed)
Returns => 250
So complex code, yes, but simple to use, a one liner!, at the end of the day.
A Final Remark
I’m sure some of you are looking at this code and saying to yourselves that this is very complex when compared to the VBA or PowerShell approaches, so why use it at all? This is a very valid statement! BUT, when I release my future articles on GDI you will start to see why it is worth the extra coding headaches as it opens other doors that no other approach does. So be patient and you will be rewarded.
A Few Resources on the Subject
