public PhotoViewModel(PhotoMetadata photoMetadata) { Caption = photoMetadata.Caption; Timestamp = photoMetadata.Timestamp; Tags = string.Join(" ", photoMetadata.Tags.Select(t => $"#{t}")); Photo = ImageSource.FromFile(photoMetadata.FileName); }
private static string ExtractDescription(IReadOnlyList <PhotoMetadata> metadata, string url, DateTime creationDate) { string description = string.Empty; PhotoMetadata desc = metadata.FirstOrDefault(predicate: item => StringComparer.InvariantCultureIgnoreCase.Equals(x: item.Name, y: MetadataNames.COMMENT)); if (desc != null) { description = desc.Value; } if (!string.IsNullOrWhiteSpace(description)) { description += ". "; } description += "Source : "; description += url; description += " Photo taken by Mark Ridgwell"; if (creationDate != DateTime.MinValue) { description += " (" + creationDate.ToString(format: "yyyy-MM-dd") + ")"; } description += "."; return(description); }
private Photo WriteMetadataToPhoto(Photo photo, PhotoMetadata metadata) { photo.Camera = metadata.Camera; photo.Aperture = metadata.Aperture; photo.DateTaken = metadata.DateTaken; photo.ExposureTime = metadata.ExposureTime; photo.Flash = metadata.Flash; photo.Iso = metadata.Iso; return(photo); }
private void listBoxMetadata_MouseDoubleClick(object sender, MouseButtonEventArgs e) { PhotoMetadata localPhotoMetadata = (sender as ListBox).SelectedItem as PhotoMetadata; if (localPhotoMetadata.Title == "URL") { System.Windows.Clipboard.SetText(localPhotoMetadata.Description); UrlCopied.Content = "URL Copied!"; } else { UrlCopied.Content = ""; } }
public static DateTime ExtractCreationDate(IReadOnlyList <PhotoMetadata> metadata) { PhotoMetadata dateTaken = metadata.FirstOrDefault(predicate: candidate => candidate.Name == MetadataNames.DATE_TAKEN); if (dateTaken == null) { return(DateTime.MinValue); } if (DateTime.TryParse(s: dateTaken.Value, out DateTime value)) { return(value); } return(DateTime.MinValue); }
private static PhotoMetadata GeneratePhotoData(Random R) { var result = new PhotoMetadata() { Camera = DBGeneratorUtils.AnyFromArray(R, cameras), Name = DBGeneratorUtils.AnyFromArray(R, namePrefix) + DBGeneratorUtils.AnyFromArray(R, nameBase) + ".jpg", CameraSettings = GetCameraSettings(R), Date = new DateTime(2004, 1, 1).AddDays(R.Next(365 * 16)), }; (result.Longitude, result.Latitude) = GetRandomLatLong(R); int pixelIdx = R.Next(pixelWidths.Length); result.WidthPx = pixelMap[pixelWidths[pixelIdx]]; result.HeightPx = pixelMap[pixelHeights[pixelIdx]]; return(result); }
public PhotoMetadata GetMetadata(IFormFile file) { if (file == null) { throw new ArgumentException("Input file cannot be null!"); } var metadata = new PhotoMetadata(); using (var ms = new MemoryStream()) { file.CopyTo(ms); ms.Seek(0, SeekOrigin.Begin); var result = ImageMetadataReader.ReadMetadata(ms); // obtain the Exif directories var exifIdDirectory = result.OfType <ExifIfd0Directory>().FirstOrDefault(); var exifSubIfDirectory = result.OfType <ExifSubIfdDirectory>().FirstOrDefault(); if (exifIdDirectory != null) { var camera = exifIdDirectory.GetDescription(ExifIfd0Directory.TagMake) ?? "Unknown"; var model = exifIdDirectory.GetDescription(ExifIfd0Directory.TagModel) ?? "Unknown"; metadata.Camera = $"{camera} - {model}"; var takenDate = exifIdDirectory.GetDescription(ExifIfd0Directory.TagDateTime); DateTime dateTime; if (DateTime.TryParse(takenDate, out dateTime)) { metadata.DateTaken = dateTime; } } if (exifSubIfDirectory != null) { var subIfdDescriptor = new ExifSubIfdDescriptor(exifSubIfDirectory); metadata.ExposureTime = subIfdDescriptor.GetExposureTimeDescription(); metadata.Aperture = subIfdDescriptor.GetApertureValueDescription(); metadata.Flash = subIfdDescriptor.GetFlashDescription(); metadata.Iso = subIfdDescriptor.GetIsoEquivalentDescription(); } } return(metadata); }
private void PopulateDatabase() { using (var photoColorDB = new PhotoColorContext()) { if (!photoColorDB.DatabaseExists()) { photoColorDB.CreateDatabase(); } if (photoColorDB.PhotoColors.Count() != this.MaximumPhotoQuantity) { // build photo palette dictionary MediaLibrary library = new MediaLibrary(); IEnumerable <Picture> photos = library.Pictures.AsEnumerable().Take(this.MaximumPhotoQuantity); this.photoDictionary = new List <PhotoMetadata>(); foreach (Picture photo in photos) { BitmapImage sourceImage = new BitmapImage(); sourceImage.SetSource(photo.GetThumbnail()); WriteableBitmap sourceBitmap = new WriteableBitmap(sourceImage); Color averageColor = sourceBitmap.GetAverageColor(); if (!photoColorDB.PhotoColors.Any(x => x.PhotoName != photo.Name)) { var newPhotoMetadata = new PhotoMetadata { PhotoName = photo.Name, PhotoColor = averageColor.ToString() }; photoColorDB.PhotoColors.InsertOnSubmit(newPhotoMetadata); this.photoDictionary.Add(newPhotoMetadata); } } photoColorDB.SubmitChanges(); GoogleAnalytics.EasyTracker.GetTracker().SendEvent("Database updated", "The database was updated.", string.Empty, 0); } else { this.photoDictionary = photoColorDB.PhotoColors.ToList <PhotoMetadata>(); } } }
public FrancePhoto(PhotoMetadata metadata, IDecoder <PhotoMetadata> decoder) => Photo = new Photo(metadata, decoder);
public PolandPhoto(PhotoMetadata metadata, IDecoder <PhotoMetadata> decoder) => Photo = new Photo(metadata, decoder);
public Photo(PhotoMetadata metadata, IDecoder <PhotoMetadata> decoder) { Name = metadata.Name; WidthPx = decoder.Decode(metadata.WidthPx); HeightPx = decoder.Decode(metadata.HeightPx); }
public PhotoViewModel(PhotoMetadata photoMetadata) { Description = photoMetadata.Description; FileName = photoMetadata.BlobName; Photo = ImageSource.FromFile(Path.Combine(FileSystem.CacheDirectory, $"{photoMetadata.BlobName}.jpg")); }
public static async Task <(GenerationReturn generationReturn, PhotoMetadata metadata)> PhotoMetadataFromFile( FileInfo selectedFile, IProgress <string> progress) { progress?.Report("Starting Metadata Processing"); selectedFile.Refresh(); if (!selectedFile.Exists) { return(await GenerationReturn.Error("File Does Not Exist?"), null); } var toReturn = new PhotoMetadata(); progress?.Report("Getting Directories"); var exifSubIfDirectory = ImageMetadataReader.ReadMetadata(selectedFile.FullName) .OfType <ExifSubIfdDirectory>().FirstOrDefault(); var exifDirectory = ImageMetadataReader.ReadMetadata(selectedFile.FullName).OfType <ExifIfd0Directory>() .FirstOrDefault(); var iptcDirectory = ImageMetadataReader.ReadMetadata(selectedFile.FullName).OfType <IptcDirectory>() .FirstOrDefault(); var gpsDirectory = ImageMetadataReader.ReadMetadata(selectedFile.FullName).OfType <GpsDirectory>() .FirstOrDefault(); var xmpDirectory = ImageMetadataReader.ReadMetadata(selectedFile.FullName).OfType <XmpDirectory>() .FirstOrDefault(); toReturn.PhotoCreatedBy = exifDirectory?.GetDescription(ExifDirectoryBase.TagArtist) ?? string.Empty; if (string.IsNullOrWhiteSpace(toReturn.PhotoCreatedBy)) { toReturn.PhotoCreatedBy = xmpDirectory?.XmpMeta?.GetArrayItem(XmpConstants.NsDC, "creator", 1)?.Value ?? string.Empty; } if (string.IsNullOrWhiteSpace(toReturn.PhotoCreatedBy)) { toReturn.PhotoCreatedBy = iptcDirectory?.GetDescription(IptcDirectory.TagByLine) ?? string.Empty; } var createdOn = exifSubIfDirectory?.GetDescription(ExifDirectoryBase.TagDateTimeOriginal); if (string.IsNullOrWhiteSpace(createdOn)) { var gpsDateTime = DateTime.MinValue; if (gpsDirectory?.TryGetGpsDate(out gpsDateTime) ?? false) { if (gpsDateTime != DateTime.MinValue) { toReturn.PhotoCreatedOn = gpsDateTime.ToLocalTime(); } } else { toReturn.PhotoCreatedOn = DateTime.Now; } } else { var createdOnParsed = DateTime.TryParseExact( exifSubIfDirectory.GetDescription(ExifDirectoryBase.TagDateTimeOriginal), "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate); toReturn.PhotoCreatedOn = createdOnParsed ? parsedDate : DateTime.Now; } var isoString = exifSubIfDirectory?.GetDescription(ExifDirectoryBase.TagIsoEquivalent); if (!string.IsNullOrWhiteSpace(isoString)) { toReturn.Iso = int.Parse(isoString); } toReturn.CameraMake = exifDirectory?.GetDescription(ExifDirectoryBase.TagMake) ?? string.Empty; toReturn.CameraModel = exifDirectory?.GetDescription(ExifDirectoryBase.TagModel) ?? string.Empty; toReturn.FocalLength = exifSubIfDirectory?.GetDescription(ExifDirectoryBase.TagFocalLength) ?? string.Empty; toReturn.Lens = exifSubIfDirectory?.GetDescription(ExifDirectoryBase.TagLensModel) ?? string.Empty; if (toReturn.Lens == string.Empty || toReturn.Lens == "----") { toReturn.Lens = xmpDirectory?.XmpMeta?.GetProperty(XmpConstants.NsExifAux, "Lens")?.Value ?? string.Empty; } if (toReturn.Lens == string.Empty || toReturn.Lens == "----") { toReturn.Lens = xmpDirectory?.XmpMeta?.GetProperty(XmpConstants.NsCameraraw, "LensProfileName")?.Value ?? string.Empty; if (toReturn.Lens.StartsWith("Adobe (")) { toReturn.Lens = toReturn.Lens.Substring(7, toReturn.Lens.Length - 7); if (toReturn.Lens.EndsWith(")")) { toReturn.Lens = toReturn.Lens.Substring(0, toReturn.Lens.Length - 1); } } } if (toReturn.Lens == "----") { toReturn.Lens = string.Empty; } toReturn.Aperture = exifSubIfDirectory?.GetDescription(ExifDirectoryBase.TagAperture) ?? string.Empty; toReturn.License = exifDirectory?.GetDescription(ExifDirectoryBase.TagCopyright) ?? string.Empty; if (string.IsNullOrWhiteSpace(toReturn.License)) { toReturn.License = xmpDirectory?.XmpMeta?.GetArrayItem(XmpConstants.NsDC, "rights", 1)?.Value ?? string.Empty; } if (string.IsNullOrWhiteSpace(toReturn.License)) { toReturn.License = iptcDirectory?.GetDescription(IptcDirectory.TagCopyrightNotice) ?? string.Empty; } var shutterValue = new Rational(); if (exifSubIfDirectory?.TryGetRational(37377, out shutterValue) ?? false) { toReturn.ShutterSpeed = ExifHelpers.ShutterSpeedToHumanReadableString(shutterValue); } else { toReturn.ShutterSpeed = string.Empty; } //The XMP data - vs the IPTC - will hold the full Title for a very long title (the IPTC will be truncated) - //for a 'from Lightroom with no other concerns' export Title makes the most sense, but there are other possible //metadata fields to pull from that could be relevant in other contexts. toReturn.Title = xmpDirectory?.XmpMeta?.GetArrayItem(XmpConstants.NsDC, "title", 1)?.Value; if (string.IsNullOrWhiteSpace(toReturn.Title)) { toReturn.Title = iptcDirectory?.GetDescription(IptcDirectory.TagObjectName) ?? string.Empty; } //Use a variety of guess on common file names and make that the title - while this could result in an initial title //like DSC001 style out of camera names but after having experimented with loading files I think 'default' is better //than an invalid blank. if (string.IsNullOrWhiteSpace(toReturn.Title)) { toReturn.Title = Path.GetFileNameWithoutExtension(selectedFile.Name).Replace("-", " ").Replace("_", " ") .SplitCamelCase(); } toReturn.Summary = iptcDirectory?.GetDescription(IptcDirectory.TagObjectName) ?? string.Empty; //2020/3/22 - Process out a convention that I have used for more than a decade of pre-2020s do yyMM at the start of a photo title or in the //2020s yyyy MM at the start - hopefully this is matched specifically enough not to accidentally trigger on photos without this info... The //base case of not matching this convention is that the year and month from photo created on are added to the front of the title or if the //title is blank the photo created on is put as a timestamp into the title. One of the ideas here is to give photos as much of a chance //as possible to have valid data for an automated import even when a detail like timestamp title is probably better replaced with something //more descriptive. if (!string.IsNullOrWhiteSpace(toReturn.Title) && toReturn.Title.StartsWith("2")) { var possibleTitleDate = Regex.Match(toReturn.Title, @"\A(?<possibleDate>\d\d\d\d[\s-]\d\d[\s-]*).*", RegexOptions.IgnoreCase).Groups["possibleDate"].Value; if (!string.IsNullOrWhiteSpace(possibleTitleDate)) { try { var tempDate = new DateTime(int.Parse(possibleTitleDate.Substring(0, 4)), int.Parse(possibleTitleDate.Substring(5, 2)), 1); toReturn.Summary = $"{toReturn.Title.Substring(possibleTitleDate.Length, toReturn.Title.Length - possibleTitleDate.Length)}"; toReturn.Title = $"{tempDate:yyyy} {tempDate:MMMM} {toReturn.Title.Substring(possibleTitleDate.Length, toReturn.Title.Length - possibleTitleDate.Length)}"; progress?.Report("Title updated based on 2yyy MM start pattern for file name"); } catch { progress?.Report("Did not successfully parse 2yyy MM start pattern for file name"); } } } else if (!string.IsNullOrWhiteSpace(toReturn.Title) && (toReturn.Title.StartsWith("0") || toReturn.Title.StartsWith("1"))) { try { if (Regex.IsMatch(toReturn.Title, @"\A[01]\d\d\d\s.*", RegexOptions.IgnoreCase)) { var year = int.Parse(toReturn.Title.Substring(0, 2)); var month = int.Parse(toReturn.Title.Substring(2, 2)); var tempDate = year < 20 ? new DateTime(2000 + year, month, 1) : new DateTime(1900 + year, month, 1); toReturn.Summary = $"{toReturn.Title.Substring(5, toReturn.Title.Length - 5)}"; toReturn.Title = $"{tempDate:yyyy} {tempDate:MMMM} {toReturn.Title.Substring(5, toReturn.Title.Length - 5)}"; progress?.Report("Title updated based on YYMM start pattern for file name"); } } catch { progress?.Report("Did not successfully parse YYMM start pattern for file name"); } } else if (Regex.IsMatch(toReturn.Title, @".*[\s-][01]\d\d\d\z", RegexOptions.IgnoreCase)) { try { var year = int.Parse(toReturn.Title.Substring(toReturn.Title.Length - 4, 2)); var month = int.Parse(toReturn.Title.Substring(toReturn.Title.Length - 2, 2)); var tempDate = year < 20 ? new DateTime(2000 + year, month, 1) : new DateTime(1900 + year, month, 1); toReturn.Summary = $"{toReturn.Title.Substring(0, toReturn.Title.Length - 5)}"; toReturn.Title = $"{tempDate:yyyy} {tempDate:MMMM} {toReturn.Title.Substring(0, toReturn.Title.Length - 5)}"; progress?.Report("Title updated based on YYMM end pattern for file name"); } catch { progress?.Report("Did not successfully parse YYMM end pattern for file name"); } } else if (Regex.IsMatch(toReturn.Title, @".*[\s-]\d\d\d\d[\s-]\d\d\z", RegexOptions.IgnoreCase)) { var possibleTitleDate = Regex.Match(toReturn.Title, @".*[\s-](?<possibleDate>\d\d\d\d[\s-]\d\d)\z", RegexOptions.IgnoreCase) .Groups["possibleDate"].Value; if (!string.IsNullOrWhiteSpace(possibleTitleDate)) { try { var tempDate = new DateTime(int.Parse(possibleTitleDate.Substring(0, 4)), int.Parse(possibleTitleDate.Substring(5, 2)), 1); toReturn.Summary = $"{toReturn.Title.Substring(0, toReturn.Title.Length - possibleTitleDate.Length)}"; toReturn.Title = $"{tempDate:yyyy} {tempDate:MMMM} {toReturn.Title.Substring(0, toReturn.Title.Length - possibleTitleDate.Length)}"; progress?.Report("Title updated based on 2yyy MM end pattern for file name"); } catch { progress?.Report("Did not successfully parse 2yyy MM end pattern for file name"); } } } else { toReturn.Title = string.IsNullOrWhiteSpace(toReturn.Title) ? toReturn.PhotoCreatedOn.ToString("yyyy MMMM dd h-mm-ss tt") : $"{toReturn.PhotoCreatedOn:yyyy} {toReturn.PhotoCreatedOn:MMMM} {toReturn.Title}"; } //Order is important here - the title supplies the summary in the code above - but overwrite that if there is a //description. var description = exifDirectory?.GetDescription(ExifDirectoryBase.TagImageDescription) ?? string.Empty; if (!string.IsNullOrWhiteSpace(description)) { toReturn.Summary = description; } //Add a trailing . to the summary if it doesn't end with ! ? . if (!toReturn.Summary.EndsWith(".") && !toReturn.Summary.EndsWith("!") && !toReturn.Summary.EndsWith("?")) { toReturn.Summary = $"{toReturn.Summary}."; } //Remove multi space from title and summary if (!string.IsNullOrWhiteSpace(toReturn.Title)) { toReturn.Title = Regex.Replace(toReturn.Title, @"\s+", " ").TrimNullToEmpty(); } if (!string.IsNullOrWhiteSpace(toReturn.Summary)) { toReturn.Summary = Regex.Replace(toReturn.Summary, @"\s+", " ").TrimNullToEmpty(); } var xmpSubjectKeywordList = new List <string>(); var xmpSubjectArrayItemCount = xmpDirectory?.XmpMeta?.CountArrayItems(XmpConstants.NsDC, "subject"); if (xmpSubjectArrayItemCount != null) { for (var i = 1; i <= xmpSubjectArrayItemCount; i++) { var subjectArrayItem = xmpDirectory?.XmpMeta?.GetArrayItem(XmpConstants.NsDC, "subject", i); if (subjectArrayItem == null || string.IsNullOrWhiteSpace(subjectArrayItem.Value)) { continue; } xmpSubjectKeywordList.AddRange(subjectArrayItem.Value.Replace(";", ",").Split(",") .Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim())); } } xmpSubjectKeywordList = xmpSubjectKeywordList.Distinct().ToList(); var keywordTagList = new List <string>(); var keywordValue = iptcDirectory?.GetDescription(IptcDirectory.TagKeywords)?.Replace(";", ",") ?? string.Empty; if (!string.IsNullOrWhiteSpace(keywordValue)) { keywordTagList.AddRange(keywordValue.Replace(";", ",").Split(",") .Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim())); } if (xmpSubjectKeywordList.Count == 0 && keywordTagList.Count == 0) { toReturn.Tags = string.Empty; } else if (xmpSubjectKeywordList.Count >= keywordTagList.Count) { toReturn.Tags = string.Join(",", xmpSubjectKeywordList); } else { toReturn.Tags = string.Join(",", keywordTagList); } if (!string.IsNullOrWhiteSpace(toReturn.Tags)) { toReturn.Tags = Db.TagListJoin(Db.TagListParse(toReturn.Tags)); } return(await GenerationReturn.Success($"Parsed Photo Metadata for {selectedFile.FullName} without error"), toReturn); }
public ItalyPhoto(PhotoMetadata metadata, IDecoder <PhotoMetadata> decoder) => Photo = new Photo(metadata, decoder);