アイキャッチ画像をWebPに一括変換する方法

2021/02/27
14
thumbnail
画像:Technology vector created by stories - www.freepik.com

きっかけはこちらのひき太郎さんの記事。

BLOGGER投稿一覧などの画像をJavaScriptでwebpに変えてみた

最近は日記系の記事投稿が続いたので今日はBLOGGER関連の記事でも書こうかな。少し前から画像ファイルを webp 形式に書き換える作業を試していました。

WebPについて初めてちゃんと知り、コードを見てインスピレーションを受け、アイキャッチ画像のWebP変換方法を思いつきました。

早速トップページのアイキャッチ画像を全てWebPに置き換えたみたところ、PageSpeed Insightsのスコアがモバイルで5点ほど、PCで2点ほど上がりました。WebPすごい!

ということで、今回はアイキャッチ画像をWebPに一括変換する方法をご紹介します。

※今回の内容は少し専門的なので、テンプレートいじりに慣れている方のみおすすめします。

WebP(ウェッピー)とは?

WebPというのは、高い圧縮率を誇る次世代の画像形式です。通常のJPEG画像などに比べ、同じ画質でもサイズを大きく抑えることができます。

開発元であるGoogleの発表によると、ほぼ同等の画質で通常のPNG, JPGよりも3割ほどファイルサイズを圧縮できるそうです。

しかも、WebPは非可逆圧縮でありながら透過やアニメーションにも対応しているというすごいフォーマット。現在はほぼすべての主要ブラウザでサポートされているため、導入に関しても大きなデメリットはありません。

Bloggerでの画像WebP化

なんと、Bloggerではアップロードした画像のURLを一部変更するだけで簡単にWebP形式に変換することができます。Bloggerさん優秀すぎますね。(WebPの開発元がGoogleで良かった!)

具体的には、画像URLの解像度指定"s〇〇"の部分を"s〇〇-rw"にするだけでOKです。本当にこれだけ??と疑ってしまいますが、画像を保存しようとするとちゃんとWebP形式になっていることが確認できます。

このありがたい仕組みを利用し、トップページの画像をWebPに変換します。

実行手順

私のテンプレートはいじりまくっていて参考にならないので、方針と手順のみお伝えします。

まず、今回一番の肝となるのはトップページの投稿表示部分にJavaScriptを組み込み、読み込み時にリアルタイムでWebP画像表示用のHTMLを出力するということです。独自タグを組み合わせた内部処理を行うことで、画像を二重読み込みしたりすることなく表示できます。

※補足

あくまでリアルタイムの変換なので、一度設置すればそれ以降は外しても自動的にWebP画像になるというわけではありません。ご注意ください。

では、早速手順のほうを見ていきます。

手順1

トップページの投稿表示部分を以下のような構成にします。

<b:loop values='data:posts' var='post' index='i'>
  <div class='top-post'>
    <b:if cond='data:post.thumbnailUrl'>
      <picture class='eyecatch'></picture>
      <!-- スクリプト設置部分 -->
    <b:else/>
      <!-- No Image 画像 -->
    </b:if>
    ...
  </div>
</b:loop>

補足:QooQをご使用の場合

テーマでQooQを使っている場合は、まずid='list'の部分を探してループ部分を以下のように書き換えることになります。

<div id='list'>
  <b:loop values='data:posts' var='post' index='i'>
    <b:include data='post' name='post'/>
  </b:loop>
</div>

サムネ設定やスクリプト設置を行う本体部分は、<b:includable id='post' var='post'>タグで囲まれている部分です。下の画像を参考に探してみてください。

説明画像1

手順2

手順1のスクリプト設置場所(pictureタグ直下)に、次のスクリプトを設置します。

<script type='text/javascript'>
  (function() {
    const idx = <data:i/>;
    let imgurl = "<data:post.thumbnailUrl/>";
    let imgurl_webp; // WebP画像URL
    if (imgurl.match(/\/s[0-9]+-.*\//)) { // 旧URL
      imgurl_webp = imgurl.replace(/\/s[0-9]+-.*\//, '/w320-h180-n-rw-e365/');
      imgurl = imgurl.replace(/\/s[0-9]+-.*\//, '/w320-h180-n-e365/');
    } else if (imgurl.match(/=s[0-9]+-.*$/)) { // 新URL
      imgurl_webp = imgurl.replace(/=s[0-9]+-.*$/, '=w320-h180-n-rw-e365');
      imgurl = imgurl.replace(/=s[0-9]+-.*$/, '=w320-h180-n-e365');
    } else if (imgurl.match(/default.jpg/)) {  // YouTubeサムネ対策
      imgurl = imgurl.replace('default.jpg', 'mqdefault.jpg');
      imgurl_webp = imgurl.replace('/vi/', '/vi_webp/').replace('.jpg', '.webp');
    } else { // 例外処理
      imgurl_webp = "<data:post.firstImageUrl/>";
      imgurl = imgurl_webp;
    }
    let eyecatch = document.getElementsByClassName('eyecatch')[idx];
    let html = '';
    html += '&lt;source srcset="' + imgurl_webp + '" type="image/webp"/&gt;';
    html += '&lt;img alt="アイキャッチ" loading="lazy" width="320" height="180" src="' + imgurl + '"/&gt;';
    eyecatch.innerHTML = html;
  }());
</script>

スクリプトでは、ループ毎に各投稿のサムネ画像URLを<data:post.thumbnailUrl/>により取得し、そのURLを書き換えてWebP画像URLを作っています。

URL処理後はHTMLを出力し、対応する投稿のpictureタグに中身を出力します。

追記(2021/7/4)

水の中にはサメがいる!」さんの記事を参考にさせて頂き、YouTubeサムネ画像のWebP化にも対応しました。

注意点として、動画によってはWebP形式のサムネイルが表示できないものがあります。その場合は、スクリプトのYouTubeサムネ対策部分を次のように置き換えてください。

    } else if (imgurl.match(/default.jpg/)) {  //YouTubeサムネ対策
      imgurl = imgurl.replace('default.jpg', 'mqdefault.jpg');
      imgurl_webp = imgurl.replace('/vi/', '/vi_webp/').replace('.jpg', '.webp');
↓↓
    } else if (imgurl.match(/default.jpg/)) {  //YouTubeサムネ対策
      imgurl = imgurl.replace('default.jpg', 'mqdefault.jpg');
      imgurl_webp = imgurl;

手順3

トップページの投稿一覧が正しく表示されるか確認してください。

うまく動かないときは、コードの構成ミスや打ち間違いがないかチェックしてみてください。

補足:画像表示に関して

今回のコードでは、IE等WebP形式に対応していない一部ブラウザのためにpictureタグで画像が切り替わるようにしています。

そのためWebPに対応しているブラウザではsourceタグのWebP画像が、そうでないものはimgタグの通常画像が自動的に表示されます。

余談

ModernizrというJavaScriptライブラリを使用すると、CSSのbackground-imageで背景化しているものに関しても画像の切り替えができるようになります。本記事では割愛しますが、WebP画像を背景として設定したい方はぜひチェックしてみてください。

14件のコメント
確かに-rwだけつけるwebpファイルに変わることが印象的です。トップページだけでなく、Bloggerに投稿したすべての画像も、この方法が食われるようです。
https://1.bp.blogspot.com/-zutUvwo6nO0/YDo7EUbL3bI/AAAAAAAACuU/W61LuB5mm8QdK2xA-tWoKBtZLflnJTVPwCLcBGAsYHQ/s500-rw/eyecatch.jpg
すぐJavaScriptですべての画像リンク一括変換を試して見なければなりません。
BINUBALLさん、コメントありがとうございます。-rwオプション、便利ですよね。

記事本体の画像一括変換も考えているので、出来たらまた記事にしようと思います。
こんばんは。
実は先日こちらのページソースを覗いてみた時に、トップページのサムネをWebp変換させるスクリプトを導入されてるのに気づき、記事で解説してくれないかなと密かに期待をしておりました(笑)
早速導入してみたところ、特に問題もないようでスコアも上がって非常に満足しております。ありがとうございましたm(_ _)m

ちなみに当方の環境(QooQ)ではこのように b:include タグを囲ってる b:loop を書き換える必要があったようです。
これに気づくのに結構遠回りしました(^^;

<b:loop values='data:posts' var='post'>
<b:include data='post' name='post'/>
</b:loop>

<b:loop values='data:posts' var='post' index='i'>
<b:include data='post' name='post'/>
</b:loop>
こんにちは^^先日はブログのフォローとコメントありがとうございますm(__)m
僕のブログ記事が何か思考のキッカケになったのであれば幸いです。JavaScriptのことをよく知らずに手探りで書いていたコードなのでお恥ずかしいところですが^^;

僕は正規表現でゴチャゴチャしていましたがmatchメソッドがスマートで良い感じですね^^
QooQだと記事表示部分が関数化されていましたけど、他のテーマだと違うものなのかぁ。

ちなみに僕はvarの方が面倒臭くなくて便利だから…と使用していましたが、やっぱりletやconstで宣言する癖をつけておいた方が良いみたいです。
ふじやんさん、コメントありがとうございます。無事導入できたとのことで何よりです(^^)

具体的なテーマに基づいた解説ができなかったのですが、b:loopの件も自己解決されたようで安心しました。問題の箇所について、後でQooQのテーマを確認して補足を加えておこうと思います。
ひき太郎さん、こんにちは。こちらこそフォローとコメント頂きありがとうございます。

WebPについてはほとんど知らなかったもので、記事を拝見してとても勉強になりました。詳しく書いてくださっていたおかげですんなりと理解でき、今回の記事に繋げることができました。

var宣言の件、面倒くさがって無難に多用していたのですがご指摘の通りです。勉強を重ねて、使い分けもしっかりできるように頑張っていこうと思います(^^;)
こんにちは。こちらの記事や他ブログの派生記事を参考に自分のブログでも利用させてもらっています。

私の環境では「data:post.thumbnailUrl/」で取得した一部のURLが「.../s72-c/...」の形式ではなく「...=s72-w400-c-h300」のようになってしまいwebp化がうまく適用されない事象がみられました。

自分でも対策を考えているところですが、情報共有のためご報告させていただきます。
>namimoriさん
こんにちは。ご報告いただきありがとうございます。

問題の件ですが、「手順2」のコードを一部修正したのでご確認の程よろしくお願いいたします。複数パターンのURLに対応できるよう、正規表現を変更しました。

コード変更後も問題が改善しない場合、お手数ですがWebP化がうまくいかない画像のURLを教えていただけますと幸いです。よろしくお願いいたします。
Fumaさん

早速のご対応ありがとうございます。

新コードを導入しましたところ(画像サイズはw480-h240に変更しています)、問題となっていたdata:post.thumbnailUrlでの取得URL
「https://blogger.googleusercontent.com/img/a/AVvXsEi-0kHbLlDF1fIBvUM0w8Ugl7eoawr2MkgILsDrsVDMUKeCeUB01L9dFz7vOLWj3nP7ghZ7Aszli8kWmI5gEs9KiIJLGw-ZraiEzV2cfsTdPcbmjyFdt6o0I6CVg6oxUmeMFL1YBrTIqIXwqtMrLGIN_-S4vstwgqxCmvXOe5WzyJX-CKMLBe3ubtmCuw=s72-w400-c-h300」
に対しては、
「https://blogger.googleusercontent.com/img/a/(略)=w480-h240-n-rw-e365」
と変換されwebp化されました。

しかし、今度は旧コードで問題なかったURL
「https://1.bp.blogspot.com/-88sVGSqMvxI/YZ_Kv0NHldI/AAAAAAAACqU/sSsTajTNwakBRat6fGiYFEUz1qpAZizRQCLcBGAsYHQ/s72-c/P_20211126_023503.jpg」

「https://1.bp.blogspot.com/(略)/w480-h240-n-rw-e365」
と変換されてしまいwebp化できませんでした。

なお、以下のURL
「https://blogger.googleusercontent.com/img/a/AVvXsEjmylv8CJaWvgQrjRxE3mnnVKJq2_o1bgLl2CYfEQuOaGtRuuOhk5k6mFSL3_fC0SrMq0a9lHPBHXID0yVNLr7aCAKhsaSjsAR3BjfC8I4EALtf1oD3EqObqjTnxsJvQsc2g3Yz80RVVLBKDobEUwshrjN3IsQJQA61LXZVrFuBPzwX5SAnrCOqW3UVDg=s72-c」
はいずれのコードでも
「https://blogger.googleusercontent.com/img/a/(略)=w480-h240-n-e365」
と変換され問題なくwebp化できます。

最初のコメントでのURLの書き方が伝わりにくかったかもしれません。申し訳ないです。
取り急ぎご報告まで。
>namimoriさん
詳しくご報告いただきありがとうございます。原因が判明しました。

先程のコードですが、焦って正規表現の指定を間違えていたようです(汗)

新URLと旧URLを分けて処理するように修正したので、今度こそは問題ないと思います。何度も恐縮ですが、ご確認の程よろしくお願いいたします。
Fumaさん
修正版導入してみました。全記事のサムネイルにて正常にwebp化できました!
いまのところ自分のブログではサムネイルURLは、

新URLの末尾「=s72-c」「=s72-w数値-c-h数値」および
旧URLの画像ファイル名直前に「/s72-c/」「/s72-w数値-c-h数値/」

の4パターンがありました。
この4パターンに対応できる条件分岐と正規表現を自分でも書いてみましたが、Fumaさんが書かれたコードの方がスマートに思えたのでFumaさんの方をありがたく使わせていただきます。
正規表現の勉強にもなりました。ありがとうございました。
>namimoriさん
ご連絡ありがとうございます。
正常に動作しているようで良かったです(^^)
こんばんは。
新URL対応のコードにアップデートされたとのことで、当記事で紹介しているコードもそれに合わせて変更させて頂きました。ちなみにこちらでもテストしてみたところ、新旧URL及び変則的なパラメータでも問題なく動作しました。
https://fujilogic.blogspot.com/2020/09/speedup-customize.html#ps1
>ふじやんさん
こんばんは。
コードの変更とテストをして頂きありがとうございます。
ふじやんさんの環境でも問題ないようで、とても安心しました。