create account

EXIF data with a pelican-photos Gallery by jeffmackinnon

View this thread on: hive.blogpeakd.comecency.com
· @jeffmackinnon ·
$12.55
EXIF data with a pelican-photos Gallery
## [Originally posted at jeffmackinnon.com](https://jeffmackinnon.com/getting-exif-data-in-the-galley-with-pelican-photos.html)
<p class="share">Share this article on: 
  <span><a class="" href="https://twitter.com/intent/tweet?text=EXIF data with a pelican-photos Gallery&amp;url=https://jeffmackinnon.com/getting-exif-data-in-the-galley-with-pelican-photos.html&amp;via=jeffmackinnon" target="_blank" title="Share on Twitter"><i class="fab fa-twitter"></i> Twitter</a></span>
<span><a class="" href="https://www.linkedin.com/sharing/share-offsite/?url=https://jeffmackinnon.com/getting-exif-data-in-the-galley-with-pelican-photos.html" target="_blank" title="Share via Linkedin"><i class="icon brands fa-linkedin"></i> Linkedin</a></span>
<span><a class="" href="mailto:?subject=EXIF data with a pelican-photos Gallery&amp;body=Way back in the day, when I was using Flickr as one of my daily visits, I really enjoyed learning … - https://jeffmackinnon.com/getting-exif-data-in-the-galley-with-pelican-photos.html" target="_blank" title="Share via Email"><i class="fas fa-envelope"></i> Email</a></span>
</p>
<img src="https://jeffmackinnon.com/photos\thefog/screenshot2022-03-07-090425a.jpg" style="max-width:100%; display: block; margin: 0px auto;"/>
</header>
<div class="entry-content">
<p>Way back in the day, when I was using <a class="reference external" href="https://www.flickr.com/photos/jeffmackinnon/">Flickr</a> as one of my daily visits, I really enjoyed learning HOW these amazing photographers made these pictures happen through the exif data. This is where I learned about the affect of aperature, etc. I would copy the settings with my old Canon XSi and grow.</p>
<p>When I added the galleries to this site with the <a class="reference external" href="https://github.com/pelican-plugins/photos">pelican-photos</a> the only way to do this was adding an exif.txt file to each folder. There is a recommended third-party software to do it, but I didn't find it intuitive and gave up.</p>
<p>This weekend however, I had a very little bit of time and decided to see what file metadata I could pull using python.</p>
<div class="section" id="using-python-to-extract-exif-data">
<h2>Using Python to extract EXIF data</h2>
<p>I tried the <tt class="docutils literal">piexif</tt> module without much luck, and then found this <a class="reference external" href="https://gist.github.com/jpstroop/58a21d02370c8ba34dc8f0fdd4206d70">GIST</a> from <a class="reference external" href="https://gist.github.com/jpstroop/">@jpstroop</a> that did most of the work for me.</p>
<pre class="code python literal-block">
<span class="k">def</span> <span class="nf">_map_key</span><span class="p">(</span><span class="n">k</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">TAGS</span><span class="p">[</span><span class="n">k</span><span class="p">]</span>
    <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">GPSTAGS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">k</span><span class="p">)</span>

<span class="c1"># Creates a dictionary of image EXIF meta data from an image, borrowed from a github gist</span>
<span class="k">def</span> <span class="nf">get_exif</span><span class="p">(</span><span class="n">image_path</span><span class="p">):</span>
    <span class="n">metadata</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">with</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">image_path</span><span class="p">)</span> <span class="k">as</span> <span class="n">i</span><span class="p">:</span>
        <span class="n">info</span> <span class="o">=</span> <span class="n">i</span><span class="o">.</span><span class="n">_getexif</span><span class="p">()</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="p">[</span> <span class="n">metadata</span><span class="o">.</span><span class="fm">__setitem__</span><span class="p">(</span><span class="n">_map_key</span><span class="p">(</span><span class="n">k</span><span class="p">),</span> <span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">info</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="p">]</span>
        <span class="k">return</span> <span class="n">metadata</span>
    <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
        <span class="k">return</span> <span class="kc">None</span>
</pre>
<p>I use the exact fucntions from @jpstroop.</p>
</div>
<div class="section" id="walking-and-writing-with-python">
<h2>Walking and writing with Python</h2>
<p>The next step was to figure out how to walk all the directories in my photo gallery and make sure that I was getting them all, for that I do this:</p>
<pre class="code python literal-block">
<span class="c1"># The directory of the source photos, the same as PHOTO_LIBRARY in pelicanconf.py</span>
<span class="c1"># I run this in a WSL instance, but pelican is run on the host windows machine, hence the sample directory</span>
<span class="nb">dir</span> <span class="o">=</span> <span class="s1">'/mnt/c/Users/jeff/Pictures'</span>

<span class="k">for</span> <span class="n">root</span><span class="p">,</span> <span class="n">subdirectories</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="nb">dir</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">subdirectory</span> <span class="ow">in</span> <span class="n">subdirectories</span><span class="p">:</span>
        <span class="nb">print</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">subdirectory</span><span class="p">))</span>
</pre>
<p>This is goes through each directory and prints the path. I don't need that for the final product, but I like knowing that something is happening when I run the script, so I kept it.</p>
</div>
<div class="section" id="creating-a-text-file-with-everything">
<h2>Creating a text file with everything</h2>
<p>Once I made sure that was working the way that I hoped, I wrote a function that will be called for every subdirectory. I called it <tt class="docutils literal">write_exif_file(directory)</tt>, this creates the text file and then loops over every .jpg file there and writes the exif data in the way needed for <tt class="docutils literal"><span class="pre">pelican-photos</span></tt> and that I think looks "good". <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[*]</a></p>
<p>That function looks like this: <a class="footnote-reference" href="#footnote-2" id="footnote-reference-2">[†]</a></p>
<pre class="code python literal-block">
<span class="k">def</span> <span class="nf">write_exif_file</span><span class="p">(</span><span class="n">directory</span><span class="p">):</span>
<span class="c1"># Open the exif.txt file, create if it doesn't exist, in the current folder.</span>
<span class="n">txt</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">directory</span><span class="o">+</span><span class="s1">'/exif.txt'</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span>

<span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">directory</span><span class="p">):</span>

    <span class="c1"># check the files which are end with specific extension</span>
    <span class="c1"># Everything that I want to have EXIF information for is a jpg, but you can add others too.</span>
    <span class="k">if</span> <span class="n">file</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">".jpg"</span><span class="p">):</span>
        <span class="c1"># Need to iterate through the files in the list and pass each to the</span>
        <span class="n">image</span> <span class="o">=</span> <span class="n">get_exif</span><span class="p">(</span><span class="n">directory</span> <span class="o">+</span><span class="s1">'/'</span><span class="o">+</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">file</span><span class="p">))</span>
        <span class="n">txt</span><span class="o">.</span><span class="n">write</span><span class="p">(</span>
            <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">file</span><span class="p">)</span> <span class="o">+</span> <span class="s1">': '</span> <span class="o">+</span>
            <span class="nb">str</span><span class="p">(</span><span class="n">image</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'Model'</span><span class="p">))</span> <span class="o">+</span>
            <span class="s1">' with a '</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">image</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'LensModel'</span><span class="p">))</span> <span class="o">+</span>
            <span class="s1">' - '</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">image</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'ExposureTime'</span><span class="p">))</span> <span class="o">+</span> <span class="s1">'s, '</span> <span class="o">+</span> <span class="c1"># I want to change this to fractions, but it works for now.</span>
            <span class="s1">'f/'</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">image</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'FNumber'</span><span class="p">))</span> <span class="o">+</span>
            <span class="s1">' at ISO-'</span> <span class="o">+</span>  <span class="nb">str</span><span class="p">(</span><span class="n">image</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'ISOSpeedRatings'</span><span class="p">))</span> <span class="o">+</span>
            <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span>
            <span class="p">)</span>

<span class="c1"># Close the text file now that we are done with it.</span>
<span class="n">txt</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">return</span> <span class="kc">None</span>
</pre>
<p>For now I'm only including:</p>
<ul class="simple">
<li>Model,</li>
<li>Lens,</li>
<li>Exposure,</li>
<li>F-Stop, and</li>
<li>ISO</li>
</ul>
<p>I may add GPS to them in the future, but as for the settings needed to replicate these shots with your own camera, I think this is enough.</p>
</div>
<div class="section" id="finding-the-code-snippet">
<h2>Finding the code snippet</h2>
<p>I created a <a class="reference external" href="https://gist.github.com/Jeffmackinnon">GIST</a> for this code snippet here - <a class="reference external" href="https://gist.github.com/Jeffmackinnon/92c747b30a873129a28cddacfc61fbe1">pelican-photos-create-exif-files</a>. Until this weekend I didn't even know that GIST was a site. As I go through creating these little scripts for myself I am way more likely to neeed a function, or code-snippet than an entire repo. I will probably be adding some more here as I go along, as a backup storage if nothing else.</p>
<p>If you have any suggestions on how to make this "slicker". If you think its useful and want to copy/paste it as a function in the plugin be my guest. I don't have the bandwidth right now to figure out how to do a proper pull-request for the plugin, or the expereince to know how to update the code in a way that won't break everything else.</p>
<p class="rubric">Footnotes</p>
<table class="docutils footnote" frame="void" id="footnote-1" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[*]</a></td><td>There is still some work to do there, especially for the exposure time. I want it to be fractional for less than a second, but its "good enough" for this iteration.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="footnote-2" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-2">[†]</a></td><td>If anyone knows CSS and wants to help me add syntac highlighting to this theme, let me know.</td></tr>
</tbody>
</table>
</div>

## [Originally posted at jeffmackinnon.com](https://jeffmackinnon.com/getting-exif-data-in-the-galley-with-pelican-photos.html)
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
properties (23)
authorjeffmackinnon
permlinkexif-data-with-a-pelican-photos-gallery
categorygithub
json_metadata{"app":"peakd/2022.02.6","format":"markdown","tags":["github","code-snippet","blog","neoxian","palnet"],"users":["jpstroop","jpstroop."],"image":["https://jeffmackinnon.com/photos\\thefog/screenshot2022-03-07-090425a.jpg"]}
created2022-03-07 16:58:00
last_update2022-03-07 16:58:00
depth0
children3
last_payout2022-03-14 16:58:00
cashout_time1969-12-31 23:59:59
total_payout_value6.284 HBD
curator_payout_value6.267 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length13,753
author_reputation6,638,762,858,188
root_title"EXIF data with a pelican-photos Gallery"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id111,106,710
net_rshares11,436,092,109,420
author_curate_reward""
vote details (39)
@beerlover ·
<div class='pull-right'>https://files.peakd.com/file/peakd-hive/beerlover/yiuU6bdf-beerlover20gives20BEER.gif<p><sup><a href='https://hive-engine.com/?p=market&t=BEER'>View or trade </a> <code>BEER</code>.</sup></p></div><center><br> <p>Hey @jeffmackinnon, here is a little bit of <code>BEER</code> from @isnochys for you. Enjoy it!</p> <p>Did you know that <a href='https://dcity.io/city'></b>you can use <b>BEER</b> at dCity game</a> to **buy dCity NFT cards** to rule the world.</p> </center><div></div>
properties (22)
authorbeerlover
permlinkre-jeffmackinnon-exif-data-with-a-pelican-photos-gallery-20220308t222932733z
categorygithub
json_metadata{"app":"beerlover/2.0"}
created2022-03-08 22:29:33
last_update2022-03-08 22:29:33
depth1
children0
last_payout2022-03-15 22:29:33
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length507
author_reputation25,804,489,777,676
root_title"EXIF data with a pelican-photos Gallery"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id111,149,925
net_rshares0
@hivebuzz ·
Congratulations @jeffmackinnon! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s):

<table><tr><td><img src="https://images.hive.blog/60x70/http://hivebuzz.me/@jeffmackinnon/upvotes.png?202203312046"></td><td>You distributed more than 38000 upvotes.<br>Your next target is to reach 39000 upvotes.</td></tr>
</table>

<sub>_You can view your badges on [your board](https://hivebuzz.me/@jeffmackinnon) and compare yourself to others in the [Ranking](https://hivebuzz.me/ranking)_</sub>
<sub>_If you no longer want to receive notifications, reply to this comment with the word_ `STOP`</sub>



**Check out the last post from @hivebuzz:**
<table><tr><td><a href="/hive-122221/@hivebuzz/pud-202204"><img src="https://images.hive.blog/64x128/https://i.imgur.com/805FIIt.jpg"></a></td><td><a href="/hive-122221/@hivebuzz/pud-202204">Hive Power Up Day - April 1st 2022</a></td></tr></table>

###### Support the HiveBuzz project. [Vote](https://hivesigner.com/sign/update_proposal_votes?proposal_ids=%5B%22199%22%5D&approve=true) for [our proposal](https://peakd.com/me/proposals/199)!
properties (22)
authorhivebuzz
permlinknotify-jeffmackinnon-20220331t210641
categorygithub
json_metadata{"image":["http://hivebuzz.me/notify.t6.png"]}
created2022-03-31 21:06:42
last_update2022-03-31 21:06:42
depth1
children0
last_payout2022-04-07 21:06:42
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length1,135
author_reputation369,429,367,030,730
root_title"EXIF data with a pelican-photos Gallery"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id111,868,120
net_rshares0
@isnochys ·
Thank you for your [witness vote](https://hivesigner.com/sign/account-witness-vote?witness=isnochys&approve=1)!
 Have a !BEER on me!
To Opt-Out of my witness beer program just comment !STOP below
properties (22)
authorisnochys
permlinkre-exif-data-with-a-pelican-photos-gallery-20220308t222809z
categorygithub
json_metadata"{"app": "beem/0.24.26"}"
created2022-03-08 22:28:12
last_update2022-03-08 22:28:12
depth1
children0
last_payout2022-03-15 22:28:12
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length195
author_reputation47,895,031,347,965
root_title"EXIF data with a pelican-photos Gallery"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id111,149,895
net_rshares0