oozcitak / exiflibrary

A .Net Standard library for editing Exif metadata
MIT License
131 stars 48 forks source link

Trouble setting Date Taken tag on a PNG file. #108

Closed rgelb closed 1 year ago

rgelb commented 1 year ago

I am trying to set the Date Taken tag on a PNG file unsuccessfully.

image

I've tried these 3 ExifTags but don't seem to change anything about the file.

DateTime dateTaken = DateTime.Parse("1/1/2022");
string filePath = "IMG_3837.PNG";
ImageFile exifImage = ImageFile.FromFile(filePath);
exifImage.Properties.Set(ExifTag.DateTimeDigitized, dateTaken);
exifImage.Properties.Set(ExifTag.DateTimeOriginal, dateTaken);
exifImage.Properties.Set(ExifTag.PNGCreationTime, dateTaken);
exifImage.Save(filePath);

After this the dialog box looks the same - no changes to the Date Taken portion.

What am I missing?

P.S. Same happens with .gif files.

heikow10 commented 1 year ago

Hi @rgelb, I am only guessing. Did you try to set ExifTag.DateTime?

rgelb commented 1 year ago

@heikow10 Sorry, I omitted it in the original post. Yes, I've tried ExifTag.DateTime. No change.

heikow10 commented 1 year ago

@rgelb Ok, maybe I can make one more guess: Try to set the property ExifTag.DateTime as string in the format: "yyyy:MM:dd HH:mm:ss".

exifImage.Properties.Set(ExifTag.DateTime, dateTaken.ToString("yyyy:MM:dd HH:mm:ss"));

rgelb commented 1 year ago

I tried the following with no success:

ImageFile exifImagePng = ImageFile.FromFile(filePath);

exifImagePng.Properties.Set(ExifTag.DateTimeOriginal, dateTaken.ToString("yyyy:MM:dd HH:mm:ss"));
exifImagePng.Properties.Set(ExifTag.DateTimeDigitized, dateTaken.ToString("yyyy:MM:dd HH:mm:ss"));
exifImagePng.Properties.Set(ExifTag.DateTime, dateTaken.ToString("yyyy:MM:dd HH:mm:ss"));
exifImagePng.Properties.Set(ExifTag.PNGCreationTime, dateTaken.ToString("yyyy:MM:dd HH:mm:ss"));
exifImagePng.Properties.Set(ExifTag.PNGTimeStamp, dateTaken.ToString("yyyy:MM:dd HH:mm:ss"));

exifImagePng.Save(filePath);

I then read it back via exifImage.Properties.Get(...) and got null for every exifTag. I think there is an issue with processing PNGs.

I tried the same tags (DateTimeOriginal,DateTimeDigitized,DateTime) with ImageSharp library and that worked, sort of. With ImageSharp, I am able to read the values back as well. However, the odd thing is that still nothing shows up in the windows Properties dialog.

So I cleared out all Exif Tags from the file and changed the Date Taken in the Properties dialog manually. Then I read back the Exif tags using both ImageSharp and ExifLib and nothing showed up. Windows probably stores that value somewhere else.

Finally, I tried the Windows API Codec Pack and that library is able to read the value that I entered into Properties dialog:

var shell = Microsoft.WindowsAPICodePack.Shell.ShellObject.FromParsingName(fi.FullName);
var data = shell.Properties?.System?.ItemDate;
Console.WriteLine(data.Value.ToString());

Now I need to figure out how to exactly write to that value. I haven't found a way to do it with WindowsAPICodePack.

Super confusing mess.

heikow10 commented 1 year ago

Ok, now I don't have an idea anymore. I always worked with jpeg files when using this library. Hope you will find a solution for your problem! Or maybe someone with more experience with this library can help you.

rgelb commented 1 year ago

Yes, jpegs work fine. I think Exif is either not a thing for PNGs or just not well supported.

I did end up finding a solution for PNGs and GIFs. I set the Xmp Profile for the photos, which Google Photos appears to understand (which was my goal all along) and places them in the proper date range.

Now I only need to find a solution to setting Exif or Xmp profile for .mov and .m4v files and then I'll be set.

dxball commented 1 year ago

I know this issue has been closed, but I still want to leave a way to add Date Taken tag to a PNG image file.

// write
ImageFile exifImagePng = ImageFile.FromFile(filePath);
exifImagePng.Properties.Set(new PNGText(ExifTag.PNGCreationTime, "Creation Time", dateTaken.ToString("yyyy:MM:dd HH:mm:ss"), false));
exifImagePng.Save(filePath);
// read
ImageFile exifImagePng = ImageFile.FromFile(filePath);
dateTaken = DateTime.ParseExact((string)imageFile.Properties.Get(ExifLibrary.ExifTag.PNGCreationTime).Value, "yyyy:MM:dd HH:mm:ss", null, System.Globalization.DateTimeStyles.None);
Bebz0r commented 1 year ago
ImageFile exifImagePng = ImageFile.FromFile(filePath);
exifImagePng.Properties.Set(new PNGText(ExifTag.PNGCreationTime, "Creation Time", dateTaken.ToString("yyyy:MM:dd HH:mm:ss"), false));
exifImagePng.Save(filePath);

Thanks @dxball , this worked for me. Do you have the logic behind it ? In my case, it's the DateTime Original that I need to overwrite. Just like ExifTag.DateTime, doing a :

img.Properties.Set(ExifTag.DateTimeOriginal, newDate);

... does nothing :'(

I tried ImageSharp but as I'm developping for Android, it worked but was way too slow (20 secs+ to load one image) :

                            // Slow as hell v
                            using (var img = SixLabors.ImageSharp.Image.Load(aDriveFile.FullPath))
                            {
                                img.Metadata.ExifProfile.SetValue(SixLabors.ImageSharp.Metadata.Profiles.Exif.ExifTag.DateTimeOriginal, newDate.Value.ToString("yyyy:MM:dd HH:mm:ss"));
                                img.Save(aDriveFile.FullPath);
                            }