A Million Little Pieces Of My Mind

NamtiraLib

SuperImages

By: Paul S Cilwa Posted: 4/10/2026 Page Views: 21
Hashtags: #Namtira #VisualBasic #VBNET #ClassLibrary #NamtiraLib #SuperImages #Image #Crop #Stretch #Cover #Fit #EXIF
Extension methods for cropping, stretching, covering, and fitting images, plus EXIF property handling.
Estimated reading time: 12 minute(s) (2623 words)

SuperImages provides extension methods for common image operations—cropping, stretching, covering, and fitting—as well as a scale calculator class and a comprehensive EXIF property reader/writer for working with image metadata.

Module SuperImages
MemberParametersExample
IsImageaFile As FileInfoIf myFile.IsImage() Then ...
IsImageaFilename As StringIf "photo.jpg".IsImage() Then ...
CropanImage As Image, DesiredRect As Rectangleimg.Crop(rect)
CropanImage As Image, DesiredHeight, DesiredWidthimg.Crop(100, 200)
CropanImage As Image, FromX, FromY, DesiredHeight, DesiredWidthimg.Crop(10, 10, 100, 200)
StretchanImage As Image, DesiredHeight, DesiredWidthimg.Stretch(100, 200)
StretchanImage As Image, DesiredSize As Sizeimg.Stretch(mySize)
CoveranImage As Image, DesiredHeight, DesiredWidthimg.Cover(100, 200)
CoveranImage As Image, DesiredSize As Sizeimg.Cover(mySize)
FitanImage As Image, DesiredHeight, DesiredWidthimg.Fit(100, 200)
FitanImage As Image, DesiredSize As Sizeimg.Fit(mySize)
SaveAsIconanImage As Image, TargetPathname As Stringimg.SaveAsIcon("icon.ico")
CopyResizedaFile As FileInfo, TargetPath, NewHeight, NewWidth, RetainProperties (opt), Stretch (opt)CopyResized(f, "out.jpg", 600, 800)
ScaleImageOldImage As Image, TargetHeight, TargetWidth, Stretch (opt)ScaleImage(img, 600, 800)
Class ImageScaleCalculator
MemberParametersExample
NewaSourceSize As Size (opt), aTargetSize As Size (opt), aMode As Modes (opt)Dim c As New ImageScaleCalculator(src, tgt, Modes.Cover)
ModesStretch, Cover, Fit
AdjustedTargetRectc.AdjustedTargetRectRectangle
Class ImageProperties
MemberParametersExample
NewBitmap As System.Drawing.BitmapDim ip As New ImageProperties(bmp)
NewFileName As StringDim ip As New ImageProperties("photo.jpg")
IsPropertyDefinedID As Int32ip.IsPropertyDefined(&H320)
CloneToTarget As ImagePropertiesoldProps.CloneTo(newProps)
Titleip.TitleString
Descriptionip.DescriptionString
Countip.CountInt16
Imports System.IO Imports System.Runtime.CompilerServices Imports System.Runtime.Serialization Imports System.Text

IsImage

Extension methods that check whether a file has a recognized image extension (.jpg, .jpeg, .png, .bmp, .gif). The String overload wraps the file path in a FileInfo and delegates to the primary overload.

Public Module SuperImages <Extension()> Public Function IsImage(aFile As FileInfo) As Boolean If aFile.Exists Then Select Case aFile.Extension.LCase ' We can use any of these file types Case ".jpg", ".jpeg", ".png", ".bmp", ".gif" Return True Case Else Return False End Select Else Return False End If End Function <Extension()> Public Function IsImage(aFilename As String) As Boolean Return IsImage(New FileInfo(aFilename)) End Function End Module

Crop

Three overloads for cropping an image. The Rectangle overload clamps the crop area to the image bounds, then draws the selected region into a new bitmap. The two-parameter form crops from the origin; the four-parameter form crops from an arbitrary point.

<Extension()> Public Function Crop(anImage As Image, DesiredRect As Rectangle) As Image With DesiredRect .Width = Math.Min(.Width, anImage.Width) .Height = Math.Min(.Height, anImage.Height) End With Dim Result As New Bitmap(DesiredRect.Width, DesiredRect.Height) Using grp = Graphics.FromImage(Result) grp.DrawImage(anImage, New Rectangle(0, 0, DesiredRect.Width, DesiredRect.Height), DesiredRect, GraphicsUnit.Pixel) End Using Return Result End Function <Extension()> Public Function Crop(anImage As Image, DesiredHeight As Int16, DesiredWidth As Int16) As Image Dim DesiredRect As New Rectangle(0, 0, DesiredHeight, DesiredWidth) Return Crop(anImage, DesiredRect) End Function <Extension()> Public Function Crop(anImage As Image, FromX As Int16, FromY As Int16, DesiredHeight As Int16, DesiredWidth As Int16) As Image Dim DesiredRect As New Rectangle(FromX, FromY, DesiredHeight, DesiredWidth) Return Crop(anImage, DesiredRect) End Function

Stretch

Resizes an image to exact dimensions without preserving the aspect ratio. The Int16 overload constructs a Size and delegates to the Size overload.

<Extension()> Public Function Stretch(anImage As Image, DesiredHeight As Int16, DesiredWidth As Int16) As Image Dim DesiredSize As New Size(DesiredHeight, DesiredWidth) Return Stretch(anImage, DesiredSize) End Function <Extension()> Public Function Stretch(anImage As Image, DesiredSize As Size) As Image Return New Bitmap(anImage, DesiredSize.Width, DesiredSize.Height) End Function

Cover

Scales the image so it completely fills the target dimensions (like CSS background-size: cover). The image is scaled up until both axes meet or exceed the target, then centered so any overflow is clipped evenly.

<Extension()> Public Function Cover(anImage As Image, DesiredHeight As Int16, DesiredWidth As Int16) As Image Dim DesiredSize As New Size(DesiredHeight, DesiredWidth) Return Cover(anImage, DesiredSize) End Function <Extension()> Public Function Cover(anImage As Image, DesiredSize As Size) As Image Dim R As New ImageScaleCalculator(anImage.Size, DesiredSize, ImageScaleCalculator.Modes.Cover) Dim Result = New Bitmap(DesiredSize.Width, DesiredSize.Height) Using grp = Graphics.FromImage(Result) grp.DrawImage(anImage, R.AdjustedTargetRect.Left, R.AdjustedTargetRect.Top, R.AdjustedTargetRect.Width, R.AdjustedTargetRect.Height) End Using Return Result End Function

Fit

Scales the image to fit entirely within the target dimensions (like CSS background-size: contain). The image is scaled down until both axes fit within the target, then centered so any letterbox area is even.

<Extension()> Public Function Fit(anImage As Image, DesiredHeight As Int16, DesiredWidth As Int16) As Image Dim DesiredSize As New Size(DesiredHeight, DesiredWidth) Return Fit(anImage, DesiredSize) End Function <Extension()> Public Function Fit(anImage As Image, DesiredSize As Size) As Image Dim R As New ImageScaleCalculator(anImage.Size, DesiredSize, ImageScaleCalculator.Modes.Fit) Dim Result = New Bitmap(DesiredSize.Width, DesiredSize.Height) Using grp = Graphics.FromImage(Result) grp.DrawImage(anImage, R.AdjustedTargetRect.Left, R.AdjustedTargetRect.Top, R.AdjustedTargetRect.Width, R.AdjustedTargetRect.Height) End Using Return Result End Function

SaveAsIcon

Saves a clone of the image in ICO format at the specified path.

<Extension()> Public Sub SaveAsIcon(anImage As Image, TargetPathname As String) anImage.Clone().Save(TargetPathname, ImageFormat.Icon) End Sub

CopyResized

Loads an image from disk, scales it via ScaleImage, optionally copies EXIF properties from the original, and saves the result as a JPEG.

Public Sub CopyResized(aFile As FileInfo, TargetPath As String, NewHeight As Int16, NewWidth As Int16, Optional RetainProperties As Boolean = True, Optional Stretch As Boolean = False) Dim Original As Image Dim Duplicate As Image Original = Image.FromFile(aFile.FullName) Duplicate = ScaleImage(Original, NewHeight, NewWidth, Stretch) If RetainProperties Then Dim OldTags As New ImageProperties(Original) Dim NewTags As New ImageProperties(Duplicate) OldTags.CloneTo(NewTags) End If Duplicate.Save(TargetPath.Replace(".jpeg", ".jpg"), ImageFormat.Jpeg) Original.Dispose() Duplicate.Dispose() End Sub

ScaleImage

Proportionally scales an image to fit within the given height and width, preserving the aspect ratio. If the proportional width exceeds the target width, the calculation flips to width-first.

Public Function ScaleImage(ByVal OldImage As Image, ByVal TargetHeight As Integer, ByVal TargetWidth As Integer, Optional Stretch As Boolean = False) As Image Dim NewHeight As Integer = TargetHeight Dim NewWidth As Integer = NewHeight / OldImage.Height * OldImage.Width If NewWidth > TargetWidth Then NewWidth = TargetWidth NewHeight = NewWidth / OldImage.Width * OldImage.Height End If Return New Bitmap(OldImage, NewWidth, NewHeight) End Function

ImageScaleCalculator

A helper class used by Cover and Fit. Given source and target sizes plus a mode, it computes the correct scaling ratio and a centered Rectangle for drawing. The Modes enum selects between Stretch, Cover, and Fit behaviour.

Public Class ImageScaleCalculator Public SourceSize As Size Public TargetSize As Size Public Enum Modes Stretch Cover Fit End Enum Public Mode As Modes = Modes.Fit Public Sub New(Optional aSourceSize As Size = Nothing, Optional aTargetSize As Size = Nothing, Optional aMode As Modes = Modes.Stretch) SourceSize = aSourceSize TargetSize = aTargetSize Mode = aMode End Sub Private ReadOnly Property Ratio As Double Get Dim RatioX As Double, RatioY As Double RatioX = TargetSize.Width / SourceSize.Width RatioY = TargetSize.Height / SourceSize.Height If Mode = Modes.Fit Then Return Math.Min(RatioX, RatioY) Else Return Math.Max(RatioX, RatioY) End If End Get End Property Public ReadOnly Property AdjustedTargetRect As Rectangle Get Dim Result As Rectangle Dim NewHeight As Integer, NewWidth As Integer Select Case Mode Case Modes.Stretch Result = New Rectangle(0, 0, TargetSize.Width, TargetSize.Height) Case Modes.Fit, Modes.Cover NewHeight = SourceSize.Height * Ratio NewWidth = SourceSize.Width * Ratio Dim posX As Integer = (TargetSize.Width - (SourceSize.Width * Ratio)) / 2 Dim posY As Integer = (TargetSize.Height - (SourceSize.Height * Ratio)) / 2 Result = New Rectangle(posX, posY, NewWidth, NewHeight) End Select Return Result End Get End Property End Class

ImageProperties

Wraps a Bitmap and provides read access to its EXIF metadata. Two enums define the EXIF data types and the standard property tag IDs. The CloneTo method copies all EXIF properties from one image to another, handling each data type appropriately.

Public Class ImageProperties Public Enum ExifDataTypes As Int16 Unknown = 0 UnsignedByte = 1 AsciiString = 2 UnsignedShort = 3 UnsignedLong = 4 UnsignedRational = 5 SignedByte = 6 Undefined = 7 SignedShort = 8 SignedLong = 9 SignedRational = 10 SingleFloat = 11 DoubleFloat = 12 End Enum Public Enum ExifPropertyNames As Int32 ExifIFD = &H8769 GpsIFD = &H8825 NewSubfileType = &HFE SubfileType = &HFF ImageWidth = &H100 ImageHeight = &H101 BitsPerSample = &H102 ImageTitle = &H320 ImageDescription = &H10E Copyright = &H8298 Compression = &H103 PhotometricInterp = &H106 ThreshHolding = &H107 CellWidth = &H108 CellHeight = &H109 FillOrder = &H10A DocumentName = &H10D EquipMake = &H10F EquipModel = &H110 StripOffsets = &H111 Orientation = &H112 SamplesPerPixel = &H115 RowsPerStrip = &H116 StripBytesCount = &H117 MinSampleValue = &H118 MaxSampleValue = &H119 XResolution = &H11A YResolution = &H11B PlanarConfig = &H11C PageName = &H11D XPosition = &H11E YPosition = &H11F FreeOffset = &H120 FreeByteCounts = &H121 GrayResponseUnit = &H122 GrayResponseCurve = &H123 T4Option = &H124 T6Option = &H125 ResolutionUnit = &H128 PageNumber = &H129 TransferFuncition = &H12D SoftwareUsed = &H131 DateTime = &H132 Artist = &H13B HostComputer = &H13C Predictor = &H13D WhitePoint = &H13E PrimaryChromaticities = &H13F ColorMap = &H140 HalftoneHints = &H141 TileWidth = &H142 TileLength = &H143 TileOffset = &H144 TileByteCounts = &H145 InkSet = &H14C InkNames = &H14D NumberOfInks = &H14E DotRange = &H150 TargetPrinter = &H151 ExtraSamples = &H152 SampleFormat = &H153 SMinSampleValue = &H154 SMaxSampleValue = &H155 TransferRange = &H156 JPEGProc = &H200 JPEGInterFormat = &H201 JPEGInterLength = &H202 JPEGRestartInterval = &H203 JPEGLosslessPredictors = &H205 JPEGPointTransforms = &H206 JPEGQTables = &H207 JPEGDCTables = &H208 JPEGACTables = &H209 YCbCrCoefficients = &H211 YCbCrSubsampling = &H212 YCbCrPositioning = &H213 REFBlackWhite = &H214 ICCProfile = &H8773 Gamma = &H301 ICCProfileDescriptor = &H302 SRGBRenderingIntent = &H303 ResolutionXUnit = &H5001 ResolutionYUnit = &H5002 ResolutionXLengthUnit = &H5003 ResolutionYLengthUnit = &H5004 PrintFlags = &H5005 PrintFlagsVersion = &H5006 PrintFlagsCrop = &H5007 PrintFlagsBleedWidth = &H5008 PrintFlagsBleedWidthScale = &H5009 HalftoneLPI = &H500A HalftoneLPIUnit = &H500B HalftoneDegree = &H500C HalftoneShape = &H500D HalftoneMisc = &H500E HalftoneScreen = &H500F JPEGQuality = &H5010 GridSize = &H5011 ThumbnailFormat = &H5012 ThumbnailWidth = &H5013 ThumbnailHeight = &H5014 ThumbnailColorDepth = &H5015 ThumbnailPlanes = &H5016 ThumbnailRawBytes = &H5017 ThumbnailSize = &H5018 ThumbnailCompressedSize = &H5019 ColorTransferFunction = &H501A ThumbnailData = &H501B ThumbnailImageWidth = &H5020 ThumbnailImageHeight = &H502 ThumbnailBitsPerSample = &H5022 ThumbnailCompression = &H5023 ThumbnailPhotometricInterp = &H5024 ThumbnailImageDescription = &H5025 ThumbnailEquipMake = &H5026 ThumbnailEquipModel = &H5027 ThumbnailStripOffsets = &H5028 ThumbnailOrientation = &H5029 ThumbnailSamplesPerPixel = &H502A ThumbnailRowsPerStrip = &H502B ThumbnailStripBytesCount = &H502C ThumbnailResolutionX = &H502D ThumbnailResolutionY = &H502E ThumbnailPlanarConfig = &H502F ThumbnailResolutionUnit = &H5030 ThumbnailTransferFunction = &H5031 ThumbnailSoftwareUsed = &H5032 ThumbnailDateTime = &H5033 ThumbnailArtist = &H5034 ThumbnailWhitePoint = &H5035 ThumbnailPrimaryChromaticities = &H5036 ThumbnailYCbCrCoefficients = &H5037 ThumbnailYCbCrSubsampling = &H5038 ThumbnailYCbCrPositioning = &H5039 ThumbnailRefBlackWhite = &H503A ThumbnailCopyRight = &H503B LuminanceTable = &H5090 ChrominanceTable = &H5091 FrameDelay = &H5100 LoopCount = &H5101 PixelUnit = &H5110 PixelPerUnitX = &H5111 PixelPerUnitY = &H5112 PaletteHistogram = &H5113 ExifExposureTime = &H829A ExifFNumber = &H829D ExifExposureProg = &H8822 ExifSpectralSense = &H8824 ExifISOSpeed = &H8827 ExifOECF = &H8828 ExifVer = &H9000 ExifDTOrig = &H9003 ExifDTDigitized = &H9004 ExifCompConfig = &H9101 ExifCompBPP = &H9102 ExifShutterSpeed = &H9201 ExifAperture = &H9202 ExifBrightness = &H9203 ExifExposureBias = &H9204 ExifMaxAperture = &H9205 ExifSubjectDist = &H9206 ExifMeteringMode = &H9207 ExifLightSource = &H9208 ExifFlash = &H9209 ExifFocalLength = &H920A ExifMakerNote = &H927C ExifUserComment = &H9286 ExifDTSubsec = &H9290 ExifDTOrigSS = &H9291 ExifDTDigSS = &H9292 ExifFPXVer = &HA000 ExifColorSpace = &HA001 ExifPixXDim = &HA002 ExifPixYDim = &HA003 ExifRelatedWav = &HA004 ExifInterop = &HA005 ExifFlashEnergy = &HA20B ExifSpatialFR = &HA20C ExifFocalXRes = &HA20E ExifFocalYRes = &HA20F ExifFocalResUnit = &HA210 ExifSubjectLoc = &HA214 ExifExposureIndex = &HA215 ExifSensingMethod = &HA217 ExifFileSource = &HA300 ExifSceneType = &HA301 ExifCfaPattern = &HA302 GpsVer = &H0 GpsLatitudeRef = &H1 GpsLatitude = &H2 GpsLongitudeRef = &H3 GpsLongitude = &H4 GpsAltitudeRef = &H5 GpsAltitude = &H6 GpsGpsTime = &H7 GpsGpsSatellites = &H8 GpsGpsStatus = &H9 GpsGpsMeasureMode = &HA GpsGpsDop = &HB GpsSpeedRef = &HC GpsSpeed = &HD GpsTrackRef = &HE GpsTrack = &HF GpsImgDirRef = &H10 GpsImgDir = &H11 GpsMapDatum = &H12 GpsDestLatRef = &H13 GpsDestLat = &H14 GpsDestLongRef = &H15 GpsDestLong = &H16 GpsDestBearRef = &H17 GpsDestBear = &H18 GpsDestDistRef = &H19 GpsDestDist = &H1A ImageXPComment = 40092 ImageXPTitle = 40091 End Enum

The constructors accept either a Bitmap object or a file path. IsPropertyDefined checks whether a given EXIF tag exists in the image.

Private ReadOnly MyBitmap As Bitmap Public Sub New(ByRef Bitmap As System.Drawing.Bitmap) If Bitmap Is Nothing Then Throw New ArgumentNullException(NameOf(Bitmap)) End If MyBitmap = Bitmap End Sub Public Sub New(FileName As String) MyBitmap = DirectCast(Image.FromFile(FileName), Bitmap) End Sub Public Function IsPropertyDefined(ID As Int32) As Boolean Return [Array].IndexOf(MyBitmap.PropertyIdList, ID) > -1 End Function

CloneTo iterates every EXIF property in the source image and copies it to the target, dispatching to type-specific helpers for each data type.

Public Sub CloneTo(Target As ImageProperties) Dim PropertyNames() As String = [Enum].GetNames(GetType(ExifPropertyNames)) For Each P As PropertyItem In MyBitmap.PropertyItems Dim T As PropertyItem If Target.IsPropertyDefined(P.Id) Then T = Target.MyBitmap.GetPropertyItem(P.Id) Else T = DirectCast(FormatterServices.GetUninitializedObject(GetType(Imaging.PropertyItem)), Imaging.PropertyItem) T.Id = P.Id End If Select Case P.Type Case ExifDataTypes.UnsignedByte If P.Id <> ExifPropertyNames.ImageXPComment Then ClonePropertyByte(P, T) Else ClonePropertyString(P, T) End If Case ExifDataTypes.SignedByte ClonePropertySByte(P, T) Case ExifDataTypes.UnsignedShort ClonePropertyUInt16(P, T) Case ExifDataTypes.SignedShort ClonePropertyInt16(P, T) Case ExifDataTypes.UnsignedLong ClonePropertyUInt32(P, T) Case ExifDataTypes.SignedLong ClonePropertyInt32(P, T) Case ExifDataTypes.AsciiString, ExifDataTypes.Undefined ClonePropertyString(P, T) End Select Target.MyBitmap.SetPropertyItem(T) Next End Sub

The private clone helpers handle each EXIF data type, copying the raw bytes from the source property item to the target.

Private Sub ClonePropertyByte(OldItem As PropertyItem, ByVal NewItem As PropertyItem) With NewItem .Id = OldItem.Id ReDim .Value(1) .Value(0) = OldItem.Value(0) .Len = 1 .Type = ExifDataTypes.UnsignedByte End With End Sub Private Sub ClonePropertySByte(OldItem As PropertyItem, ByVal NewItem As PropertyItem) With NewItem .Id = OldItem.Id ReDim .Value(1) .Value(0) = CSByte(OldItem.Value(0)) .Len = 1 .Type = ExifDataTypes.SignedByte End With End Sub Private Sub ClonePropertyInt16(OldItem As PropertyItem, ByVal NewItem As PropertyItem) With NewItem .Id = OldItem.Id ReDim .Value(2) .Value(0) = OldItem.Value(0) And &HFF .Value(1) = OldItem.Value(1) And &HFF00 >> 8 .Len = 2 .Type = ExifDataTypes.SignedShort End With End Sub Private Sub ClonePropertyUInt16(OldItem As PropertyItem, ByVal NewItem As PropertyItem) ClonePropertyInt16(OldItem, NewItem) NewItem.Type = ExifDataTypes.UnsignedShort End Sub Private Sub ClonePropertyInt32(OldItem As PropertyItem, ByVal NewItem As PropertyItem) With NewItem .Id = OldItem.Id ReDim .Value(4) For i As Byte = 0 To 3 .Value(i) = CByte(OldItem.Value(i)) Next .Len = 4 .Type = ExifDataTypes.SignedLong End With End Sub Private Sub ClonePropertyUInt32(OldItem As PropertyItem, ByVal NewItem As PropertyItem) ClonePropertyInt32(OldItem, NewItem) NewItem.Type = ExifDataTypes.UnsignedLong End Sub Private Sub ClonePropertyString(OldItem As PropertyItem, ByVal NewItem As PropertyItem) Dim MyEncoding As Encoding = System.Text.Encoding.ASCII With NewItem .Value = MyEncoding.GetBytes(GetPropertyString(OldItem)) .Len = .Value.Length * 2 .Type = ExifDataTypes.AsciiString End With End Sub

Private getter helpers extract typed values from raw EXIF property bytes.

Private Function GetPropertyUByte(Item As PropertyItem) As Byte Return Item.Value(0) End Function Private Function GetPropertySByte(Item As PropertyItem) As SByte Return Item.Value(0) End Function Private Function GetPropertyInt16(Item As PropertyItem) As Int16 Return Item.Value(1) << 8 Or Item.Value(0) End Function Private Function GetPropertyUInt16(Item As PropertyItem) As UInt16 Return Item.Value(1) << 8 Or Item.Value(0) End Function Private Function GetPropertyInt32(Item As PropertyItem) As Int32 Return Item.Value(1) << 8 Or Item.Value(0) End Function Private Function GetPropertyString(Item As PropertyItem) As String If Item.Value Is Nothing Then Return String.Empty Dim Encoder As System.Text.Encoding If Item.Type = ExifDataTypes.AsciiString Then Encoder = System.Text.Encoding.ASCII Else Encoder = System.Text.Encoding.Unicode End If Dim R As String = Encoder.GetString(Item.Value) If R.EndsWith(vbNullChar) Then R = R.Substring(0, R.Length - 1) Return R.ToString End Function

Three public read-only properties expose the image's title (checking multiple EXIF tags in priority order), description, and total property count.

Public ReadOnly Property Title As String Get Dim Result As String If IsPropertyDefined(ExifPropertyNames.ImageTitle) Then Result = GetPropertyString(MyBitmap.GetPropertyItem(ExifPropertyNames.ImageTitle)) If Result.Length > 0 AndAlso Result <> Description Then Return Result End If If IsPropertyDefined(ExifPropertyNames.ImageXPTitle) Then Result = GetPropertyString(MyBitmap.GetPropertyItem(ExifPropertyNames.ImageXPTitle)) If Result.Length > 0 AndAlso Result <> Description Then Return Result End If If IsPropertyDefined(ExifPropertyNames.ImageDescription) Then Result = GetPropertyString(MyBitmap.GetPropertyItem(ExifPropertyNames.ImageDescription)) If Result > "" Then Return Result End If Return String.Empty End Get End Property Public ReadOnly Property Description As String Get Dim Result As String If IsPropertyDefined(ExifPropertyNames.ImageXPComment) Then Result = GetPropertyString(MyBitmap.GetPropertyItem(ExifPropertyNames.ImageXPComment)) If Result > "" Then Return Result End If If IsPropertyDefined(ExifPropertyNames.ExifUserComment) Then Result = GetPropertyString(MyBitmap.GetPropertyItem(ExifPropertyNames.ExifUserComment)) If Result > "" Then Return Result End If Return String.Empty End Get End Property Public ReadOnly Property Count As Int16 Get Return MyBitmap.PropertyItems.Count End Get End Property End Class