Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Gary Williams 9 posts 29 karma points
    Jul 08, 2023 @ 15:28
    Gary Williams
    0

    Extract Picture Date

    I have a web site that primarily show pictures. I'd like to use the actual date the picture was taken, not the create date in Umbraco. This is especially true when I go on a trip and don't load the pictures into Umbraco until I return.

    This question has two parts, hopefully the same answer.

    I would prefer to do this as a field within Umbraco, not at render time.

    The first case is to go through all of the existing pictures and extract the date the picture was taken and upload the item in Umbraco.

    The second case is to extract the date the picture was taken when new pictures are uploaded.

    I don't believe there is such a plugin available yet (I looked). Would someone be able to point me in the right direction?

    Thanks!

  • Marc Goodson 2155 posts 14408 karma points MVP 9x c-trib
    Jul 09, 2023 @ 09:30
    Marc Goodson
    0

    Hi Gary

    There was I believe this package in V8 to add a content app to show exif data

    https://our.umbraco.com/packages/backoffice-extensions/media-info/

    source here: https://github.com/prjseal/MediaInfo

    It uses this tool: https://github.com/drewnoakes/metadata-extractor-dotnet

    to do the extracting.

    So I think from what you are describing you want to add a DateTaken property to the MediaType for Images...

    Then you need a way to populate it.

    When Media is uploaded to backoffice - the MediaService will fire the MediaSaved Notification

    https://docs.umbraco.com/umbraco-cms/reference/notifications/mediaservice-notifications

    within this you could get access to the uploaded image, read it's meta data and then update the Media Item in Umbraco with the DateTaken details...

    Then for existing Media - you could either add a custom 'Menu Item' to the MediaTree using the MenuRenderingNotification

    https://docs.umbraco.com/umbraco-cms/extending/section-trees/trees#menurenderingnotification

    to give editors ability to choose to 'Go Get PhotoTaken data' that would then do the extraction and update the media item...

    or if you want to do a full sweep of the existing Media in one go...

    ... you could use the MediaService, GetRootMedia() method to get the top level media items, and then use the .Children property of each media item to iteratively loop through the Media section, check for the phototaken date, and if it's not filled in, try and get the Media Item and extract it... depending on how much media you have... could take a while!

    https://apidocs.umbraco.com/v9/csharp/api/Umbraco.Cms.Core.Services.IMediaService.html

    regards

    Marc

  • Huw Reddick 1929 posts 6697 karma points MVP 2x c-trib
    Jul 09, 2023 @ 10:08
    Huw Reddick
    1

    Hi Gary,

    This is the code I use, it uses the metadata extractor mentioned by Marc

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using MetadataExtractor;
    using MetadataExtractor.Formats.Exif;
    using Microsoft.Extensions.Logging;
    using Umbraco.Cms.Core.Events;
    using Umbraco.Cms.Core.IO;
    using Umbraco.Cms.Core.Models;
    using Umbraco.Cms.Core.Notifications;
    using Directory = MetadataExtractor.Directory;
    
    namespace UmbracoProject1.Services;
    
    public class AddExifTagsFromImageHandler : INotificationHandler<MediaSavingNotification>
    {
        private readonly ILogger<AddExifTagsFromImageHandler> _logger;
        private readonly MediaFileManager _mediaFileManager;
    
        public AddExifTagsFromImageHandler(ILogger<AddExifTagsFromImageHandler> logger, MediaFileManager mediaFileManager)
        {
            _logger = logger;
            _mediaFileManager = mediaFileManager;
    
        }
    
        public void Handle(MediaSavingNotification notification)
        {
            foreach (var mediaItem in notification.SavedEntities)
            {
                if (mediaItem.ContentType.Alias.Equals("Image"))
                {
                    if (!mediaItem.HasIdentity)
                    {
                        try
                        {
                            _logger.LogDebug($"Sending {mediaItem.Name} to GetExifData");
                            Dictionary<string,string> exIfTags = GetExifData(mediaItem);
    
                            foreach (var exifProperty in mediaItem.Properties.Where(p=>p.Alias.StartsWith("exif")))
                            {
                                mediaItem.SetValue(exifProperty.Alias, exIfTags[exifProperty.Alias]);
                            }
                        }
                        catch (Exception e)
                        {
                            _logger.LogDebug($"{e.Message}");
                        }
    
                    }
    
    
                }
            }
        }
        private Dictionary<string,string> GetExifData(IMedia publishedItem)
        {
            var tags = new Dictionary<string, string>();
            try
            {
                using (Stream stream = _mediaFileManager.GetFile(publishedItem, out string mediaFilePath))
                {
                    IEnumerable<Directory> directories = ImageMetadataReader.ReadMetadata(stream);
                    var subIfdDirectory = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault();
                    var jpgInfo = directories.OfType<ExifIfd0Directory>().FirstOrDefault();
                    var gpsDirectory = directories.OfType<GpsDirectory>().FirstOrDefault();
                    if (gpsDirectory != null)
                    {
                        _logger.LogInformation($"Found {publishedItem.Name} gpsDirectory");
                        tags.Add("exifLocation",gpsDirectory?.GetGeoLocation()?.ToString());
                    }
                    if (subIfdDirectory != null && subIfdDirectory.ContainsTag(ExifDirectoryBase.TagDateTimeOriginal))
                    {
                        _logger.LogInformation($"Found {publishedItem.Name} TagDateTimeOriginal");
                        var dateStr = subIfdDirectory?.GetDescription(ExifDirectoryBase.TagDateTimeOriginal);
                        if (dateStr != null)
                        {
                            tags.Add("exifCreatedDate",dateStr);
                        }
                    }
                    if (jpgInfo != null && !tags.ContainsKey("exifCreatedDate"))
                    {
                        _logger.LogInformation($"Found {publishedItem.Name} jpgInfo");
                        var dateStr = jpgInfo?.GetDescription(ExifDirectoryBase.TagDateTime);
                        tags.Add("exifCreatedDate",dateStr);
                    }
                }
            }
            catch (Exception e)
            {
                return null;
            }
            return tags;
        }
    
    }
    

    My code also uses the exif location which you may want to ignore :)

  • Gary Williams 9 posts 29 karma points
    Jul 09, 2023 @ 15:01
    Gary Williams
    0

    Wow! Thank you so much Marc and Huw! I guess my Sunday won't be entirely relaxing after all!

Please Sign in or register to post replies

Write your reply to:

Draft