これまでスクリーンショットをとってそのままマークダウンに貼り付けてたんですが、なんでも画像の最適化というのをしたほうがいいらしい、と最近知りました。

どうやるのかと調べてみたところ、Cloudinaryというサービスにアップロードして取得したURL貼り付けると自動で最適化できるらしいのでやってみました。

Cloudinaryは公式のドキュメントやブログがちょっと圧倒されるくらい充実してて、どういうことができるのかまだ全然把握していません。 また画像を最適化して表示することについてもちょっと調べた限り奥が深そうです。

なのでもっといいやり方があるんじゃないかとは思いますが、とりあえず「画像の容量を減らして貼り付けるのををなるべくお手軽に処理する」あたりを目標とします。

環境

  • Hugoバージョン : 0.54.0
  • 使用テーマ : Robust

なおRobustテーマをカスタマイズするので、/themes/hugo_theme_robust 内のlayoutsフォルダをルートディレクトリのlayoutsフォルダへコピーして、コピー元のファイルではなくコピーしたファイルを編集します。

ただしすでにlayoutsフォルダ内の一部のファイルやフォルダをコピー済みの場合には、まだ存在していないファイルのみをコピーしてください。

またすでにlayoutsフォルダをまるごとコピー済みの場合には、コピーしないでください。

Cloudinaryとは

CDN(コンテンツの配信サーバー)サービス。 クラウド上に画像を保存して管理でき、画像の加工もできます。 自動で画像の最適化することもでき、また高速で配信してくれるのでウェブページの表示速度が速くなるそうです。

ちょっと使った感じだと、無料版でも個人ブログ用途なら十分余裕がありそうです。

Cloudinary公式サイト

CLoudinaryの簡単な使い方

CLoudinaryは細かいことやろうと思えばいろいろできるようです。

でも私はブログの画像の管理・変換・配信をなるべく手間をかけずにまかせたいだけなので、とりあえず最低限だけ覚えました。

  1. Cloudinaryに画像をアップロードする
  2. 生成されたURLをコピーする
  3. Hugoのショートコードにペーストする
  4. ショートコードにより画像最適化オプションを加える

これだけです。

1.は、Media Libraryの画面上に画像ファイルをドラッグ&ドロップするだけです(画像の①)。

2.は、アップロードされたファイルの右のほうにあるCopy URLアイコンをクリックするだけです(画像の②)。

Cloudinaryに画像をアップロードし生成されたURLをコピー

3.4.は後述します。

ちょっと困ったのは、画像を同じ名前で上書きアップロードしようとすると、キャッシュの関係かなかなか新しい画像が表示されないことです。ローカルの画像ならリネームしてからアップロードして違うURLを取得したほうが早いかもしれません。

Hugoショートコード

ショートコードの使い方

一般的な使い方かどうかはわかりませんが、 設定したショートコードを「がぞう」とか「くらう」とか読みを付けて単語登録して使ってます。
「くらう」→{{<img src=“” h=“” w=“” caption=“” alt=“” >}}

こっちはローカルの画像用
「がぞう」→{{<img src=“images/” h=“” w=“” caption=“” alt=“” >}}

私はまだ使いこなせてないですが、エディタでスぺニット登録して利用するのもいいと思います。

参考にしたページ

こちらブログのやり方を参考にしました。

Cloudinaryを利用したレスポンシブ配信 - SIS Lab

{{<img>}}でCloudinaryの画像とそれ以外の画像とを両方扱えるのは便利でいいですね。

一部にリンク先のコードのコピペ部分が残ってて、できたコードを載せてもいいかどうかよくわからないので、以下変更箇所のみ記述します。

リンク先のコードから変更した箇所

コードの{{else}}内の部分はRobustテーマのlayouts/shortcodes/img.htmlにもともとあったものにしました。 前半部分は基本的にリンク先のやり方をまねしていますが、自分の使い方に合わせて以下のようにしています。

img.amp.htmlではなくimg.htmlを編集

AMPというものをまだよくわかってないためです……。 layout属性はAMP特有のものらしいので削除しました。

cloudinaryのユーザー名に当たる部分を変更

置換するURLの末尾の部分を変更

Cloudinaryで生成されるURLは https://res.cloudinary.com/<ユーザー名>/image/upload/<変換オプション>/<バージョン番号>/<パス>という形です。

これに対してリンク先のコードは生成されるURLを{{$baseurl}}<変換オプション>{{$itemid}}として取得しているのですが、この{{$itemid}}がファイル名+拡張子しか取得しないので、CloudinaryのMediaLibraryでHomeに画像を置いている場合にしか画像を表示できません。 私はHomeの下にフォルダを作って画像を入れたいので、次のように変更しました。

{{ $itemid := .Get "src" | replaceRE "^https?://res.cloudinary.com/meganii/image/upload/.+/(.*)" "$1" }}

↓↓

{{ $itemid := .Get "src" | replaceRE "^https?://res.cloudinary.com/<ユーザー名>/image/upload/(.*)" "$1" }}

正規表現?もよく知りませんが、.+/(.*)だと”ファイル名+拡張子”の部分しか取得できないようです。

.+/(.*)(.*)としたことで、upload/の後ろの文字列すべてが$itemidに格納されました。

これによりCloudinaryで画像をHomeに置かずにフォルダで整理していても、src=“URLコピペ”で表示できるようになりました。

例:CloudinaryでHome > HugoBlog > 2019_03 フォルダ内にsample.pngを置いた場合、

$itemid := "<バージョン番号>/HugoBlog/2019_03/sample.png"

と代入されます。

複数のw_オプションを設定したsrcset属性を削除しw_auto、dpr_autoを使用

リンク先はsrcset属性でw_オプションの異なる複数のイメージソースを用意して環境にあった画像を読み込む方法をとっているように思われます。

しかしこれをそのまま適用してみたところ、小さい画像を貼ったときに記事スペースの横幅いっぱいに拡大されてしまいました。

私は小さい画像も貼りたいので、srcset属性を削除してsrc属性のみとし、q_auto,f_autoに加えてc_scale、w_auto、dpr_autoというオプションを付けてみました。

Image optimization

ここを見るとsrcset属性を使わなくても異なるサイズの画像を生成してくれる?のかな? なにやらお手軽そうなので取り入れてみました。

あまり詰めなくても、q_autoだけでも十分容量が削減できそうだし別にいいんじゃないかなあ、くらいに思っていたんですが、w_autodpr_autoがちゃんと自動で画像を切り替えてくれているなら儲けものかな。

最適なやり方かどうかはよくわかりませんが、ともかく画像を元の大きさより拡大されないようにできたのでよかったです。

記事のサムネイルの表示もCloudinaryの画像とローカルの画像ファイルの両方に対応する

フロントマターのthumbnailにCloudinaryのURLを設定すると、ソース表示したときに「ベースURL+CloudinaryのURL」となってしまう部分がいくつかあって、正しく表示できていないようです。

そこでRobustテーマのサムネイル表示に関係ある部分を、さっきのリンク先のショートコードと同様の条件分岐を使って書き換えていきます。

まずstyles.cssの末尾にある次の部分を削除して、

{{ range $p := .Site.RegularPages }}
  {{ with $p.Params.thumbnail }}
    .thumb-{{ $p.UniqueID }} {
      background-image: url({{ $.Site.BaseURL }}{{ . }});
    }
  {{ end }}
{{ end }}

custom.css に次のように追加します(記事のサムネ)。styles.cssでもいいけど。

{{ range $p := .Site.RegularPages }}
  {{ with $p.Params.thumbnail }}

    {{ $baseurl := "https://res.cloudinary.com/<ユーザー名>/image/upload/" }}
    {{ if hasPrefix $p.Params.thumbnail $baseurl}}
      {{ $itemid := $p.Params.thumbnail | replaceRE "^https?://res.cloudinary.com/<ユーザー名>/image/upload/(.*)" "$1" }}
      .thumb-{{ $p.UniqueID }} {
        background-image: url("{{ $baseurl }}q_auto,f_auto,c_scale,w_auto,dpr_auto/{{ $itemid }}");
      }
    {{ else }}
      .thumb-{{ $p.UniqueID }} {
        background-image: url({{ $.Site.BaseURL }}{{ . }});
      }
    {{ end }}
  {{ end }}
{{ end }}

これで記事のサムネは表示されるようになります。

つぎにsingle_meta.html の<meta property="og:image"><meta name="twitter:image">の部分を、次のように書き換え(OGPタグ)。

{{ $baseurl := "https://res.cloudinary.com/<ユーザー名>/image/upload/" }}
{{ if hasPrefix .Params.thumbnail $baseurl}}
  {{ $itemid := .Params.thumbnail | replaceRE "^https?://res.cloudinary.com/<ユーザー名>/image/upload/(.*)" "$1" }}
  <meta property="og:image" content="{{ $baseurl }}q_auto,f_auto,c_scale,w_auto,dpr_auto/{{ $itemid }}">
{{ else }}
  <meta property="og:image" content="{{ .Site.BaseURL }}{{ .Params.thumbnail | default "images/default.jpg" }}">
{{ end }}


{{ $baseurl := "https://res.cloudinary.com/<ユーザー名>/image/upload/" }}
{{ if hasPrefix .Params.thumbnail $baseurl}}
  {{ $itemid := .Params.thumbnail | replaceRE "^https?://res.cloudinary.com/<ユーザー名>/image/upload/(.*)" "$1" }}
  <meta name="twitter:image" content="{{ $baseurl }}q_auto,f_auto,c_scale,w_auto,dpr_auto/{{ $itemid }}">
{{ else }}
  <meta name="twitter:image" content="{{ .Site.BaseURL }}{{ .Params.thumbnail | default "images/default.jpg" }}">
{{ end }}

でもSNSやってないのでちゃんと表示できてるか確認してません/(^o^)\

あとsingle_json_ld.html "image""url"の部分も次のように書き換えます。

"image": {
      "@type": "ImageObject",

      {{ $baseurl := "https://res.cloudinary.com/<ユーザー名>/image/upload/" }}
      {{ if hasPrefix .Params.thumbnail $baseurl}}
        {{ $itemid := .Params.thumbnail | replaceRE "^https?://res.cloudinary.com/<ユーザー名>/image/upload/(.*)" "$1" }}
        "url": "{{ $baseurl }}q_auto,f_auto,c_scale,w_auto,dpr_auto/{{ $itemid }}",
      {{ else }}
        "url": "{{ .Site.BaseURL }}{{ .Params.thumbnail | default "images/default.png" }}",
      {{ end }}
      
      "height": 800,
      "width": 800
    },

構造化マークアップとかいうやつらしいですがよくわかりません!

OGPと構造化マークアップはよくわかってないので、これで大丈夫なのかは不明ですが、少なくともソースの表示を見る限り明らかにおかしいURLは修正されています。

最適化して表示できているかどうか確認する

ウェブページ上の画像が最適化できているかどうかどうやって確認するんだろう、と調べてもはっきり書いてあるサイトはなかなか見つかりませんでした。

でもPageSpeedInsightsというWebページの読み込み速度測定サイトで画像の最適化に問題があると指摘されるらしいので、指摘がなければOKなのかもしれません。

さっそくやってみました。

もっと減らせるぞ!と注意されているのはローカルの画像だけなので、Cloudinaryから配信している画像は問題なさそうです。

またChromeのF12を押してSourcesというタブをクリックすると、そのウェブページで読み込んでいるファイルが表示されるようなので、Cloudinaryの画像を探してみると、容量も表示されました。

このはりねずみの画像の元の容量は49kbくらいですが、13kbまで減っているので、軽量化表示には成功しているように思われます。

確認の仕方として適切なのかどうかはわかりませんが、大丈夫そうな気はします。

あとはw_autodpr_autoが効いているかどうか、つまりスマホなどで表示した際に実際にデータサイズが減っているかどうかですが、スマホもってないのでわかりません……できてたらいいなー。

おわりに

画像を最適化する手間はだいぶ減ったんじゃないかと思います。

ただ違うオプションで画像を貼り付けたい場合には、別のショートコードを作るか画像ごとに調整するかなどが必要になるかもしれません。