Functions/GenXdev.Media/Get-ImageGeolocation.cs
|
// ################################################################################
// Part of PowerShell module : GenXdev.Media // Original cmdlet filename : Get-ImageGeolocation.cs // Original author : René Vaessen / GenXdev // Version : 3.26.2026 // ################################################################################ // Copyright (c) 2026 René Vaessen / GenXdev // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ################################################################################ using System.Collections; using System.Management.Automation; namespace GenXdev.Media { [System.ComponentModel.Description(@" .SYNOPSIS Extracts geolocation data from an image file. .DESCRIPTION * Reads EXIF metadata from an image file to extract its latitude and longitude coordinates. * Supports images that contain GPS metadata in their EXIF data. * Uses the System.Drawing.Image class to load the image and parse the GPS coordinates from property items. .EXAMPLE ```powershell Get-ImageGeolocation -ImagePath ""C:\Pictures\vacation.jpg"" ``` Extracts GPS coordinates from a vacation photo. .EXAMPLE ```powershell ""C:\Pictures\vacation.jpg"" | Get-ImageGeolocation ``` Uses the pipeline to pass the image path. ")] [Cmdlet(VerbsCommon.Get, "ImageGeolocation")] [OutputType(typeof(Hashtable))] public class GetImageGeolocationCommand : PSGenXdevCmdlet { /// <summary> /// The full path to the image file to analyze /// </summary> [Parameter( Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = "Path to the image file to analyze")] [ValidateNotNullOrEmpty] public string ImagePath { get; set; } /// <summary> /// Begin processing - validate image path exists /// </summary> protected override void BeginProcessing() { // Use PowerShell Test-Path for exact path resolution behavior var scriptBlock = ScriptBlock.Create("param($path) Test-Path -LiteralPath $path"); var testResult = scriptBlock.Invoke(ImagePath); if (!(bool)testResult[0].BaseObject) { WriteError(new ErrorRecord( new FileNotFoundException($"The specified image path '{ImagePath}' does not exist."), "PathNotFound", ErrorCategory.ObjectNotFound, ImagePath)); return; } WriteVerbose($"Processing image: {ImagePath}"); } /// <summary> /// Process record - extract GPS metadata from image /// </summary> protected override void ProcessRecord() { Image image = null; try { // Load the image file WriteVerbose("Loading image file"); image = Image.FromFile(ImagePath); // Get all property items var propertyItems = image.PropertyItems; // Extract GPS metadata properties WriteVerbose("Extracting GPS metadata"); var latitudeRef = propertyItems.FirstOrDefault(pi => pi.Id == 0x0001); var latitude = propertyItems.FirstOrDefault(pi => pi.Id == 0x0002); var longitudeRef = propertyItems.FirstOrDefault(pi => pi.Id == 0x0003); var longitude = propertyItems.FirstOrDefault(pi => pi.Id == 0x0004); // Check if GPS data exists if (latitude != null && longitude != null && latitudeRef != null && longitudeRef != null) { // Calculate actual latitude and longitude values uint latNum = BitConverter.ToUInt32(latitude.Value, 0); uint latDen = BitConverter.ToUInt32(latitude.Value, 4); double lat = (double)latNum / latDen; uint lonNum = BitConverter.ToUInt32(longitude.Value, 0); uint lonDen = BitConverter.ToUInt32(longitude.Value, 4); double lon = (double)lonNum / lonDen; // Adjust for south and west hemispheres if (latitudeRef.Value[0] == (byte)'S') { lat = -lat; } if (longitudeRef.Value[0] == (byte)'W') { lon = -lon; } WriteVerbose($"GPS coordinates found: {lat}, {lon}"); var result = new Hashtable { ["Latitude"] = lat, ["Longitude"] = lon }; WriteObject(result); } else { WriteVerbose("No GPS metadata found in image"); WriteObject(null); } } catch (Exception ex) { WriteError(new ErrorRecord( ex, "ImageProcessingError", ErrorCategory.InvalidOperation, ImagePath)); } finally { if (image != null) { image.Dispose(); } } } /// <summary> /// End processing - no cleanup needed /// </summary> protected override void EndProcessing() { } } } |