public static GpsHelper FromDouble(double angleInDegrees) { //ensure the value will fall within the primary range [-180.0..+180.0] while (angleInDegrees < -180.0) { angleInDegrees += 360.0; } while (angleInDegrees > 180.0) { angleInDegrees -= 360.0; } var result = new GpsHelper { IsNegative = angleInDegrees < 0 }; //switch the value to positive angleInDegrees = Math.Abs(angleInDegrees); //gets the degree result.Degrees = (int)Math.Floor(angleInDegrees); var delta = angleInDegrees - result.Degrees; //gets minutes and seconds var seconds = (int)Math.Floor(3600.0 * delta); result.Seconds = seconds % 60; result.Minutes = (int)Math.Floor(seconds / 60.0); delta = delta * 3600.0 - seconds; //gets fractions result.Milliseconds = (int)(1000.0 * delta); return(result); }
public static void SetMetadata(string imgSourcePath, string metadata, bool fixImageOrientation = true) { var saveimage = false; try { ImageFile fileInfo; try { //Retrieve current known metadata for the image fileInfo = ImageFile.FromFile(imgSourcePath); } catch //Most likely this type of image is either not supported by the Exif library or does not have any Exif information { return; } if (!string.IsNullOrWhiteSpace(metadata)) { var defaultProperties = fileInfo.Properties.Count; //Iterate through all properties to be set on the image foreach (var geoElement in JObject.Parse(metadata)) { //Current new property has a valid value? if (!string.IsNullOrEmpty(geoElement.Value.Value <string>())) { //Is the current geolocation element supported? if (Geoloc2ExifPropertyMapper.ContainsKey(geoElement.Key)) { //Get current EXIF tag for the current geolocation property var currentExifTag = (ExifTag)Geoloc2ExifPropertyMapper[geoElement.Key]; var exifProperty = fileInfo.Properties.FirstOrDefault(p => p.IFD == IFD.GPS && p.Tag == currentExifTag); //Image does not contain this property in the metadata if (exifProperty == null) { switch (currentExifTag) { case ExifTag.GPSLatitude: var lat = GpsHelper.FromDouble(geoElement.Value.Value <double>()); var newLatProperty = new GPSLatitudeLongitude(ExifTag.GPSLatitude, lat.Degrees, lat.Minutes, lat.Seconds); fileInfo.Properties.Add(newLatProperty); var newLatRefProperty = new ExifAscii(ExifTag.GPSLatitudeRef, geoElement.Value.Value <double>() > 0 ? "N" : "S", Encoding.ASCII); fileInfo.Properties.Add(newLatRefProperty); break; case ExifTag.GPSLongitude: var lng = GpsHelper.FromDouble(geoElement.Value.Value <double>()); var newLongProperty = new GPSLatitudeLongitude(ExifTag.GPSLongitude, lng.Degrees, lng.Minutes, lng.Seconds); fileInfo.Properties.Add(newLongProperty); var newLongRefProperty = new ExifAscii(ExifTag.GPSLongitudeRef, geoElement.Value.Value <double>() > 0 ? "E" : "W", Encoding.ASCII); fileInfo.Properties.Add(newLongRefProperty); break; case ExifTag.GPSDOP: var newDopProperty = new ExifSRational(ExifTag.GPSDOP, new MathEx.Fraction32(geoElement.Value.Value <double>())); fileInfo.Properties.Add(newDopProperty); break; case ExifTag.GPSAltitude: var newAltitudeProperty = new ExifSRational(ExifTag.GPSAltitude, new MathEx.Fraction32(geoElement.Value.Value <double>())); fileInfo.Properties.Add(newAltitudeProperty); var newAltitudeRefProperty = new ExifByte(ExifTag.GPSAltitudeRef, 0); fileInfo.Properties.Add(newAltitudeRefProperty); break; case ExifTag.GPSSpeed: var newSpeedProperty = new ExifSRational(ExifTag.GPSSpeed, new MathEx.Fraction32( geoElement.Value.Value <double>() * 3.6)); //Convert to Km/h fileInfo.Properties.Add(newSpeedProperty); if (fileInfo.Properties.All(p => p.Name != ExifTag.GPSSpeedRef.ToString())) { var newSpeedRefProperty = new ExifAscii(ExifTag.GPSSpeedRef, "K", Encoding.ASCII); //Km/h fileInfo.Properties.Add(newSpeedRefProperty); } break; case ExifTag.GPSImgDirection: var newDirectionProperty = new ExifSRational(ExifTag.GPSImgDirection, new MathEx.Fraction32(geoElement.Value.Value <double>())); fileInfo.Properties.Add(newDirectionProperty); if (fileInfo.Properties.All(p => p.Name != ExifTag.GPSImgDirectionRef.ToString())) { var newDirectionRefProperty = new ExifAscii(ExifTag.GPSImgDirectionRef, "T", Encoding.ASCII); //True North fileInfo.Properties.Add(newDirectionRefProperty); } break; } } } } } //Set additional information in EXIF header if (defaultProperties < fileInfo.Properties.Count) { saveimage = true; if (fileInfo.Properties.FirstOrDefault(p => p.Name == ExifTag.Software.ToString()) == null) { var newSoftwaredProperty = new ExifAscii(ExifTag.Software, ExifDefaultSoftware, Encoding.ASCII); fileInfo.Properties.Add(newSoftwaredProperty); } if (fileInfo.Properties.FirstOrDefault(p => p.Name == ExifTag.GPSDateStamp.ToString()) == null) { var newDateStampProperty = new ExifAscii(ExifTag.GPSDateStamp, DateTime.Now.Date.ToString("yyyy:MM:dd"), Encoding.ASCII); fileInfo.Properties.Add(newDateStampProperty); } if (fileInfo.Properties.FirstOrDefault(p => p.Name == ExifTag.GPSTimeStamp.ToString()) == null) { var newTimeStampProperty = new GPSLatitudeLongitude(ExifTag.GPSTimeStamp, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second); fileInfo.Properties.Add(newTimeStampProperty); } } } //Image orientation needs correction? if (fixImageOrientation) { var imgOrientation = fileInfo.Properties.FirstOrDefault(i => i.Name == ExifTag.Orientation.ToString()); if (imgOrientation != null) { var orientationValue = BitConverter.ToUInt16(imgOrientation.Interoperability.Data, 0); if (orientationValue != (int)RotateFlipType.RotateNoneFlipNone) { var rotateFlipType = GetRotateFlipTypeByExifOrientationData(orientationValue); if (rotateFlipType != RotateFlipType.RotateNoneFlipNone) { //Get copy of current exif data from original image var exifData = fileInfo.Properties.ToArray(); //Remove thumbnail related data from original image foreach (var thumbData in exifData.Where(p => p.IFD == IFD.First || p.IFD == IFD.JFIF).ToArray()) { fileInfo.Properties.Remove(thumbData); } SaveImageFileWithRetry(fileInfo, imgSourcePath); //Flip image using (var img = Image.FromFile(imgSourcePath)) { var encoderParams = new EncoderParameters { Param = { [0] = new EncoderParameter(Encoder.Quality, 90L) } }; img.RotateFlip(rotateFlipType); img.RemovePropertyItem((int)ExifTag.Orientation - (int)IFD.Zeroth); img.Save(imgSourcePath, GetEncoder(ImageFormat.Jpeg), encoderParams); saveimage = false; } } } } } //Save changes in EXIF header if (saveimage) { SaveImageFileWithRetry(fileInfo, imgSourcePath); } } catch (Exception ex) { throw new Exception("Error in ACTransit.Framework.Imaging.SetMetadata", ex); } }