Publishing Live Photos with Jekyll and LivePhotosKit JS

I recently posted three Live Photos using LivePhotosKit JS. My blog is built with Jekyll, and I wanted the Live Photos to display correctly on large and small screens. Since getting it to work took some trial and error, and there aren’t a lot of helpful resources other than Apple’s documentation, I wrote this post to explain how I got it to work.

The Apple way

First I tried Apple’s recommended method, adding the appropriate data- attributes to a <div> element:

<div
    data-live-photo
    data-photo-src="{{ site.url }}/images/live-photos/IMG_7280.JPG"
    data-video-src="{{ site.url }}/images/live-photos/IMG_7280.MOV"
    style="width: 640px; height: 852px">         
</div>

But I ran into a problem. It looked fine on a big screen, but the picture overflowed the <div>’s parent container on the iPhone screen in portrait orientation.

  Screen shot of the webpage on macOS
It looked the way I expected on macOS.
  Screen shot of the broken webpage on iOS
On iOS... not so great.

If you want it to be viewable on different screen sizes, Apple’s method doesn’t really work.

Media queries

My first thought was to use media queries to control the size of the <div>, but LivePhotosKit complained about the <div> having a width and height of zero. After a little more experimentation, I concluded that CSS wouldn’t work. It seems that LivePhotosKit expects the <div> to have a style attribute with a non-zero width and height.

Solution

To appropriately set expectations, I’ll introduce this next part by saying that my front-end development skills are pretty amateur, and my solution isn’t elegant. This is how I finally got the Live Photos to render correctly on large and small screens.

In the post’s front matter, I listed the photo, the video and a caption for each Live Photo I wanted to display on the page:

live_photos:
    -
        photo: IMG_7280.JPG
        video: IMG_7280.MOV
        caption: Taxiing in the rain in Atlanta
    -
        photo: IMG_7337.JPG
        video: IMG_7337.MOV
        caption: Sunset at <a href="https://maps.google.com/?q=37.0046,-122.188">Shark Fin Cove</a>

    -
        photo: IMG_7341.JPG
        video: IMG_7341.MOV
        caption: There were lots of rabbits on the cliffs above the cove.

In the body of the post, I put an empty <div> to serve as the container for the Live Photos:

<div id="live-photo-container"></div>

Finally, I have an include called scripts.html that’s included in my post template. I added this to the end of scripts.html:

{% if page.live_photos %}
<script>
    $(document).ready(function() {
        var divWidth;
        var divHeight;
        if (screen.width < 640) {
            divWidth = "320px";
            divHeight = "426px";
        }
        else {
            divWidth = "640px";
            divHeight = "852px";
        }
        {% for p in page.live_photos %}
        $("#live-photo-container").append('<div data-live-photo data-photo-src="{{ site.url }}/images/live-photos/{{ p.photo }}" data-video-src="{{ site.url }}/images/live-photos/{{ p.video }}" style="width: ' + divWidth + '; height: ' + divHeight + '">');
        $("#live-photo-container").append('<p class="live-photo-caption">{{ p.caption }}</p>');
        {% endfor %}
    });
</script>
<script src="https://cdn.apple-livephotoskit.com/lpk/1/livephotoskit.js"></script>
{% endif %}

{% if page.live_photos %} ensures that the JavaScript is executed, and LivePhotosKit JS is loaded, only if the post contains Live Photos.

The script is wrapped in jQuery’s $(document).ready() function to make sure the <div> with ID live-photo-container is present before the Live Photo <div> elements are added to the page. If the screen is less than 640 pixels wide, the width is set to 320px, and the height is set to 426px. Otherwise, the width and height are set to 640px and 852px.

Then for each Live Photo defined in the post’s front matter, jQuery is used to append a <div> with the proper attributes to the <div> with ID live-photo-container. Finally, LivePhotosKit JS is loaded to do the heavy lifting.

It’s not an elegant solution. It only handles two broad screen sizes, and the Live Photo isn’t centered on iOS. But it works well enough for now.

Screen shot of the webpage rendered correctly on iOS
You can actually see the whole image on iOS now.

A few oddities

In case you want to try this for yourself, here are a few issues I encountered.

When I was testing locally on my MacBook (using bundle exec jekyll serve), Firefox was the only browser that would actually render both the photo and the video elements on macOS. Safari and Chrome just rendered the static photo and showed in place of the normal control. Neither Safari nor Chrome would play the video on iOS. They behaved in the same way as Safari and Chrome on macOS.

The Live Photos rendered correctly in all browsers (sort of; see below) only after I moved everything to my web server.

In my experience, browser compatibility wasn’t consistent with the list of supported browsers in Apple’s documentation. On macOS, Live Photos on the web are best viewed in Chrome. Safari and Firefox work, but the performance is a little worse when transitioning from photo to video.

On iOS, Safari was the only browser that worked for me, but it crashed frequently, usually after playing one of the videos for the first time. Chrome on iOS didn’t work at all for me. It crashed almost immediately on both my iPhone 6S and my iPad Pro.

A few Live Photos I took on a recent trip to California, posted using LivePhotosKit JS. To see the video, hover your mouse pointer over the “LIVE” button in the top right corner of the photo. On a phone or tablet, tap and hold the picture.

For best results, use Safari if you’re on iOS. Chrome seems to work best on macOS. It works fine on macOS but seems to be a little buggy on iOS. (Apple says Chrome may work on Android, and any of the major browsers should work on Windows, but I haven’t tried those.)

(I'm still working on getting the Live Photos to display on the front page. Click here to view them.)

Interesting fact: Newark Liberty International Airport is EWR because in the U.S., “N” can only be used by the Navy.

 Why the 'O' in San Francisco's Airport Code, SFO?

daylilies
 Jun 27, 2017 20:27
Experimenting with depth of field blur in Affinity Photo for iPad

I’ve been using Day One since February 17, 2014, and I have 5,916 entries (although the majority of those are automated entries) in four journals. I’ve recorded everything from my daily routine to job changes to vacations in it.

When I read about the new premium service, I subscribed right away. It’s a valuable service that I use every day, and I want to see it continue for many years into the future, so it’s definitely worth the cost to me. It’s also a rock-solid, dead-simple way to keep a journal, and I strongly recommend it if you’re looking for such an app. The premium service is $49.99/year, but right now it’s discounted to $34.99 for new subscribers and $24.99 for current users of Day One 2.0.