gohugoio / hugo

The world’s fastest framework for building websites.
https://gohugo.io
Apache License 2.0
75.18k stars 7.48k forks source link

Add EXIF metadata #4600

Closed bep closed 5 years ago

bep commented 6 years ago

See https://github.com/rwcarlsen/goexif

Looks a little bit early, but promising.

digitalcraftsman commented 6 years ago

Add as metadata (params?) to the image resource for JPEG and TIF.

I would expected the name params in a context where the user can add and retrieve custom data. For Exif data I would call it meta or metadata instead.

But this are just my two cents :)

bep commented 6 years ago

But this are just my two cents :)

But you are right, I didn't think. It needs its own header. This will require some thinking, I think.

regisphilibert commented 6 years ago

Metadata may be confusing with the existing implementation of .Resources metadata.

kaushalmodi commented 6 years ago

.. or just call it what it is...EXIF.

bep commented 6 years ago

So, to show you how random my priorities are. I'm going to implement this as an "experimental feature" (I will add some flag to turn it on). Not because I'm going to remove it, but because of the library I'm going to use is a little bit alpha.

There are possible additions to this (makernote data etc.), but I will start with EXIF.

The library has a JSON marshaler, but it puts everything in slices, which I guess is correct (in the sense that every field can have more than one value). Given a fairly representative image (se below), I think that will not be very user friendly for the average Hugo user. I think we rather should add a isSlice func and add all EXIF fields with 1 element as a single int etc. into a map. I think I need to read up on the EXIF spec on this to see if I can identify the "list values".

Input on the datastrcuture would be cool. I suggest adding a map to Resource, say Data (which matches nicely with Page.Data).

So: Params is custom data from the user, Data is custom data from Hugo.

This way you can safely do with $myResource.Data.EXIF and it would not crash for non-image resources. Maybe.

type EXIF struct {
Lat float64
Long float64
Date time.Time
Values map[string]interface{} // See below

/cc @digitalcraftsman @kaushalmodi @regisphilibert @onedrawingperday and gang. Input and suggestions welcome.

GPSSatelites => "06" Format: string
GPSDateStamp => "2018:04:11" Format: string
FocalPlaneResolutionUnit => 3 Format: int
ExposureMode => 0 Format: int
Contrast => 2 Format: int
GPSLongitudeRef => "E" Format: string
GPSAltitude => "70/100" Format: rational
GPSTimeStamp => ["12/1","12/1","26000/1000"] Format: rational
ShutterSpeedValue => "8965784/1000000" Format: rational
Make => "RICOH IMAGING COMPANY, LTD." Format: string
GPSLongitude => ["6/1","446111/10000","0/1"] Format: rational
DateTimeOriginal => "2018:04:11 14:12:26" Format: string
FocalLength => "1600/100" Format: rational
GPSLatitudeRef => "N" Format: string
GPSSpeedRef => "K" Format: string
GPSMapDatum => "WGS-84" Format: string
Software => "Adobe Photoshop Lightroom Classic 7.3 (Macintosh)" Format: string
ExifIFDPointer => 292 Format: int
FNumber => "9/1" Format: rational
DateTimeDigitized => "2018:04:11 14:12:26" Format: string
Sharpness => 2 Format: int
SubjectDistanceRange => 2 Format: int
GPSProcessingMethod => "ASCIIGPS" Format: undefined
XResolution => "140/1" Format: rational
ISOSpeedRatings => 100 Format: int
FocalPlaneYResolution => "83927223/32768" Format: rational
SensingMethod => 2 Format: int
GPSTrack => "16169/100" Format: rational
ApertureValue => "633985/100000" Format: rational
Flash => 16 Format: int
GPSStatus => "A" Format: string
FocalPlaneXResolution => "83927223/32768" Format: rational
SceneCaptureType => 0 Format: int
Saturation => 0 Format: int
GPSTrackRef => "T" Format: string
Model => "PENTAX K-3 II" Format: string
GPSInfoIFDPointer => 850 Format: int
GPSSpeed => "1/100" Format: rational
DateTime => "2018:05:02 16:09:05" Format: string
ExposureTime => "1/500" Format: rational
LensModel => "smc PENTAX-DA* 16-50mm F2.8 ED AL [IF] SDM" Format: string
GPSImgDirectionRef => "T" Format: string
ResolutionUnit => 2 Format: int
Artist => "bjorn.erik.pedersen@gmail.com" Format: string
ThumbJPEGInterchangeFormatLength => 11537 Format: int
ExifVersion => "0230" Format: undefined
ColorSpace => 1 Format: int
GPSAltitudeRef => 0 Format: int
YResolution => "140/1" Format: rational
MeteringMode => 5 Format: int
WhiteBalance => 0 Format: int
FocalLengthIn35mmFilm => 24 Format: int
GPSVersionID => [2,3,0,0] Format: int
GPSLatitude => ["61/1","247253/10000","0/1"] Format: rational
ThumbJPEGInterchangeFormat => 1326 Format: int
ExposureProgram => 3 Format: int
ExposureBiasValue => "0/10" Format: rational
CustomRendered => 0 Format: int
GPSImgDirection => "27339/100" Format: rational
GPSMeasureMode => "3" Format: string

Taken:  2018-04-11 14:12:26 +0200 CEST
lat, long:  61.41208833333334 ,  6.743518333333333
bep commented 6 years ago

image

Not sure what to do with the rational numbers. In the above, they are math/big.Rat which is, of course, the most precise value. That Rat has methods to convert it to a float etc., but it may be hard to use from the templates, so perhaps just convert it to the nearest float?. But there will maybe people needing this kind of precision, so ...

regisphilibert commented 6 years ago

That is really nice!

I think that will not be very user friendly for the average Hugo user. I think we rather should add a isSlice func and add all EXIF fields with 1 element as a single int etc. into a map.

Yep makes sense.

Not sure what to do with the rational numbers. In the above, they are math/big.Rat which is, of course, the most precise value.

I think people will expect raw values. I'm sure users will find ways to format it to their likings. If they cannot, maybe some template func could be introduced later on.

This will make some nice "photography" themes...

TotallyInformation commented 6 years ago

Hi, I'm afraid that I don't agree about the raw values. Most photo's and photo-using sites are not likely to want such horrible numbers to deal with. I am not even sure they may any sense at all in fact given that the difference in visual data would be infinitesimal.

F-stop differences below 0.1 are very unlikely to be useful. Shutter-speed differences below 1 thousandth of a second (maybe 1/10,000) would only be useful in limited scientific settings. Generally, cameras will use well-recognised settings since F-stop/shutter-speed interactions are well understood.

It would be worth noting that one of the leading experts on these things is Phil Harvey who has spent years developing the definitive exiftool. So worth looking at the outputs that produces.

bep commented 6 years ago

@TotallyInformation My example above is not fantastic, but I agree that for a presentation I would only want to output f2.8 it that was the aperture. I don't need gazillions of decimals and precision. That said, I have not thought too hard about what people want to use this feature for. Maybe output some JSON file as an input to some image processing library and that library really need the accuracy... I will have a look at exiftool.

TotallyInformation commented 6 years ago

No worries, I just know how easy it is for us techies to get carried away :)

I can see that a portfolio site would find this useful as would some sites that publish photos of the natural world (I have a friend who is an insect specialist for example). In those cases, telling people something about the settings that produced the photo can help in understanding.

For me personally, the only EXIF data I would want to make use of would be date and comment. I actually use IPTC tags a lot more as these provide a much richer set of metadata.

bep commented 6 years ago

Yea, well:

image

I guess float values makes most sense for most people.

For me the EXIF value is focal length, aperture and shutter speed. For me and the common blogger I guess the GPS position and date is also useful.

bep commented 6 years ago

image

So there is shutter speed value and ExposureTime...

I would say that 1/640 reads better than 0.0015625

regisphilibert commented 6 years ago

I am no photographer, but I am used to see Exposure Time and Shutter Speed Value displayed as fraction on my camera. As this how we set them, it would make sense to read them this way too, in my opinion.

kaushalmodi commented 6 years ago

So @bep says:

I would say that 1/640 reads better than 0.0015625

@regisphilibert So looks like we are in agreement here :). And I too would love to see the ExposureTime in fractions like 1/640.

I do photography by hobby, but I don't understand ExposureTime vs ShutterSpeed. I always call that 1/640 value the "shutter speed".. but here that value is 9.32..? Can someone clarify the difference here?

bep commented 6 years ago

image

I have tested a little bit more, and concluded that: If the numerator is 1 (as in 1/500), I will use the rational number, else convert it to a float. Quckly looking at the exiftool output, I'm not too far off. But remember that that is a specialist tool that the author has spent years fine-tuning ...

The "ExposureTime vs ShutterSpeed" ... there are some complex explanations online. The conclusion is: I'm using the ExposureTime.

regisphilibert commented 6 years ago

: If the numerator is 1 (as in 1/500), I will use the rational numbe

Spot on, this is what we you're used to see in our camera settings.

kaushalmodi commented 6 years ago

Coincidentally this came up in the forum: https://discourse.gohugo.io/t/how-to-use-image-orientation-with-image-processing/11823.

Looks like none of the EXIF variables listed above store the Orientation info? Or may be it's just the test image you happened to pick?

kaushalmodi commented 6 years ago

After some more digging, it looks like the Orientation flag will show up automatically if present?

https://github.com/rwcarlsen/goexif/blob/d4c99c2ae043cae162d53024b1dc50c3a189a27c/exif/fields.go#L16

kaushalmodi commented 6 years ago

I think we rather should add a isSlice func

Related: I had made a full proposal here.

and add all EXIF fields with 1 element as a single int etc. into a map.

Sounds good.

Input on the datastrcuture would be cool. I suggest adding a map to Resource, say Data (which matches nicely with Page.Data).

This way you can safely do with $myResource.Data.EXIF

+1. I think that also leaves room for possibly stuff like $myResource.Data.IPTC in future?

kaushalmodi commented 6 years ago

The "ExposureTime vs ShutterSpeed" ... there are some complex explanations online. The conclusion is: I'm using the ExposureTime.

Figured out the difference.. turned out not so complicated:

*EXIF ShutterSpeed (APEX system) aka Tv = -1.0 log2(EXIF ExposureTime in seconds)**

So, ExposureTime of 1/640 = 9.322 in ShutterSpeed (-log2(1/640)).

.. TIL.


And similarly,

*EXIF ApertureValue (APEX system) aka Av = 2.0 log2(EXIF FNumber)**

So, FNumber of 9 (f/9) = 6.34 in ApertureValue (2*log2(9)).


Reference

epadepa commented 6 years ago

Nice to see things progressing on the EXIF front! I have to say though that selling that DA AL 35/2.4 seems like a terrible mistake to me ;-) cheap but lovely lens that is as long as you are wearing ear protection.

Sticking to fractions and generally following photographic convention must the by far the most useful way forward? In terms of useful tags the following matter to me. The technical photo ones not so much.

The last one I gather might not me exif but xmp?! Being able to grab the gps data for mapping is a great feature.

bep commented 6 years ago

seems like a terrible mistake to me ;-) cheap but lovely lens that is as long as you are wearing ear protection.

I also have the 35/2.8 macro -- which is probably my sharpest lens, and just as portable.

bganderson commented 6 years ago

Would really love to see this added.

bep commented 6 years ago

Would really love to see this added.

Yea, I have an implementation floating around. But I got hindered by a bug in a third-party library (which I fixed, but I wait for a merge of a PR). I will eventually get back to it.

acahir commented 5 years ago

FYI, seems like there's a (possibly?) less "alpha" exif tool for go than what you started with:

https://github.com/dsoprea/go-exif

rdsaunders commented 5 years ago

I've recently started building a multilingual photography theme with hugo and came across this thread. Being able to use this EXIF data would be super helpful and reduce the need for an author to manually populate the data. Looks like some great progress has been made. I'd love to see this fully implemented.

Some of the fields I'd personally find helpful (with expected output format) as I've been looking at this theme, most of which you've already mentioned:

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.