Cloudinary の条件分岐変換を試してみた

大量のアセットを変換して配信する場合、この条件の場合はこの変換、そうでない場合は違う変換を適用させる、といったことができると便利です。Cloudinaryの条件分岐変換でやってみました。
2020.09.18

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Guten Morgen!ベルリンより伊藤です。

今回はCloudinaryConditional Image Transformationを試してみました。大量の画像に対して、画像の種類によって異なる変換を適用させたい場合に、条件分岐の同じ変換パラメータセットを使うことができます。

Cloudinaryでは配信URL内で変換パラメータを指定することによって、画像や動画の動的な変換を行えますが、驚くことにこの条件も変換パラメータを使って実現します。

条件分岐変換の適用例

早速、適用してみた例を見てみましょう。画像は画面キャプチャですので、画質はご容赦ください。

例1: 画像サイズが小さかったら、違う変換サイズを適用

画像が小さい場合は拡大せずに背景色でサイズを合わせ、そうでない場合は横幅に合わせてスケールします。次のように横幅を揃えて表示させつつ、画像は切り抜かず、小さい画像は拡大したくないというケースで便利です。

Cloudinary 条件分岐変換の例1

https://res.cloudinary.com/CLOUD_NAME/image/upload
  /q_auto:best ←品質 Auto:best (全体に適用)
  /if_w_lt_200,c_lpad,w_200,h_h  ←幅が200px以下なら、高さを維持、幅を200pxとなるよう背景を埋める
  /if_else,c_scale,w_200  ←そうでなければ、幅200pxとなるよう縮小
  /v1/test/path/to/file.jpg

例2: 画像に顔が含まれていたら、違う変換サイズを適用

画像に顔が含まれている場合は高さに合わせてスケール、そうでない場合では幅と高さを指定して切り抜きます。顔が含まれているかどうかで変換処理を変えたい場合に使います。

次の例では、インスタからいくつか画像を引っ張ってきて試してみました。小さい顔まできちんと認識されてオーバーレイされていて、顔の含まない風景画だけは指定した通り切り抜きされています。

Cloudinary 条件分岐変換の例2

https://res.cloudinary.com/CLOUD_NAME/image/upload
  /f_auto,q_auto  ←フォーマット・品質 Auto (全体に適用)
  /if_faces_gte_1/c_scale,h_300  ←顔が1つ以上あれば、高さ300pxへスケール
  /l_hoya_s,b_white,c_lpad,fl_region_relative,r_max,w_1.1
  /g_faces,fl_layer_apply  ←オーバーレイを顔の上に配置
  /if_else,c_fill,g_auto,h_300,w_500  ←顔がなければ、W500xH300となるよう切り抜き
  /if_end/bo_1px_solid_grey  ←画像に枠線 (全体に適用)
  /v1/path/to/file.jpg

なお、オーバーレイを顔の上に配置する g_faces パラメータは条件分岐でなくても使用できるので、「画像に顔が含まれていたら、顔にオーバーレイ」だけであれば、条件分岐しなくても実現可能です。詳しくは、オーバーレイ・アンダーレイ変換に関する次のブログをご参考ください。

◆ 参考: Cloudinaryの画像変換パラメータまとめ 〜 オーバーレイ・アンダーレイ | Developers.IO

例3: タグに応じて、ウォーターマークを適用

画像に「wm1」というタグが含まれる場合は黒文字「wm2」が含まれる場合は白文字で、幅60%、中央に半透明で "classmethod" という文字を入れます。ウォーターマークを入れたいけれど、タグ付けによって明るい画像と暗い画像で色の違うものを入れたいといったケースで役立ちます。

またインスタからいくつか引っ張った画像で試してみました。
次の例では、1つ目、2つ目は適切にタグ付与して意図した通りにウォーターマークが適用されています。一方、該当するタグがない場合はテキストオーバーレイはされず、逆に両方タグを付けると両方適用されることが確認できます。

Cloudinary 条件分岐変換の例3

https://res.cloudinary.com/CLOUD_NAME/image/upload
  /w_330   ←幅330pxへスケール (全体に適用)
  /if_!wm1!_in_tags,a_-20,co_black,fl_relative,l_text:verdana_30_bold:classmethod,o_40,w_0.6  ←タグwm1が含まれる場合
  /if_!wm2!_in_tags,a_20,co_white,fl_relative,l_text:verdana_30_bold:classmethod,o_40,w_0.6  ←タグwm2が含まれる場合
  /v1/path/to/file.jpg

解説

if 条件の指定形式

if_[条件に指定する項目]_[演算子]_[条件に指定する値] の形式で、次の演算子が使えます。

演算子 意味
eq, ne =、!=
lt, gt <, >
lte, gte <=, =>
in, nin 含む、含まない

ただし、文字列の比較である in/nin だけは、if 内での指定の順序が逆転します。

  • if_w_eq_200: 幅が200pxの場合
  • if_w_ne_200: 幅が200pxでない場合
  • if_w_lt_200: 幅が200pxより小さい場合
  • if_!sale:in_stock!_in_tags: タグに"sale"と"in_stock"を含む場合

条件に指定できる項目

if 条件に指定できる項目は、大まかに以下があります。

  • 幅: w (現在のサイズ *1)、iw (元のサイズ)
  • 高さ: h (現在のサイズ *1)、ih (元のサイズ)
  • アスペクト比: ar (現在のサイズ *1)、iar (元のサイズ)、tar ('trim'エフェクトで切り抜かれた場合)
  • メタデータ: ctx (コンテキスト *2)、md (構造*2)
  • タグ: tags
  • 検出された顔の数: fc/faces
  • ドキュメントのページ(*3): cp (現在のページ)、pc(全ページ数)
  • 元の解像度 (dpi): idn
  • 画像がイラストである可能性(写真でなく): ils(0が写真、1がイラスト)
  • TIFFファイルのレイヤー名: pgnames(in/ninで指定)

(*1) 例えば元のサイズが1000pxの画像に対してw_300/if_w_gt_200...と適用した場合、w「現在のサイズ」はif判定時点の300pxを基準とします。
(*2) コンテキストはアセットごとに個別に追加したメタデータで、構造はアカウント全体でフィールド定義されているメタデータ (参考: DAM - Metadata tab)
(*3) PDFドキュメントからの一部のページ、一部分を画像として変換することができる (参考: Uploading, Managing and Delivering PDFs)

今回、例1では幅 'w'、例2では顔の数 'faces'、例3ではタグ 'tags' を使ってます。

すべての一覧はドキュメント(Conditional Image Transformation)をご参考ください!

if_else と if_end

条件分岐変換では次の3つの要素があります。

if パラメータには上述のような条件を指定するものに加え、if_elseif_end があり、オプションで if 条件と組み合わせられます。

通常は、if 条件に合致する場合に適用する変換は、ifパラメータと同じスラッシュ区切り内で指定します。次のように、同じスラッシュ区切り内に少なくとも1つの変換パラメータがないと、URLはエラーとなります。

  • OK: /if_w_gt_500,w_300,e_red:50/
  • NG: /if_w_gt_500/w_300,e_red:50/

一方で、スラッシュ区切りの連結した変換パラメータ(次の例では w_300,e_red:50/e_blur)を適用させたい場合には、逆にifパラメータの直後でスラッシュで区切ります。この場合、連結した変換の終わりを示すために、if_else で条件に合致しない場合の変換パラメータを指定するか if_end で一連の変換パラメータの終了を示す必要があります。

  • OK: /if_w_gt_500/w_300,e_red:50/e_blur/if_else/w_300/if_end/
  • OK: /if_w_gt_500/w_300,e_red:50/e_blur/if_end/
  • NG: /if_w_gt_500,w_300,e_red:50/e_blur/if_end/
  • NG: /if_w_gt_500/w_300,e_red:50/e_blur/

変換URLを短くする

適用例で見て分かる通り、ifパラメータは条件や変換が複雑なほど長いパラメータの組み合わせになってしまいます。でも、これも名前付き変換として保存することができます!

◆ 参考: Cloudinary の Named Transformation で画像変換 URL をシンプルにする | Developers.IO

次のように、例3のウォーターマークの条件分岐変換を "wm_classmethod" として登録します。

cloudinary.api.create_transformation("wm_classmethod",
	"if_!wm1!_in_tags,a_-20,co_black,fl_relative,l_text:verdana_30_bold:classmethod,o_40,w_0.6/if_!wm2!_in_tags,a_20,co_white,fl_relative,l_text:verdana_30_bold:classmethod,o_40,w_0.6")

そうすれば、同じ変換がこんなに短いパスで適用できます。

https://res.cloudinary.com/CLOUD_NAME/image/upload
  /w_330
  /t_wm_classmethod
  /v1/path/to/file.jpg

else if はできる?

例3では、if_wm1_in_tags と if_wm2_in_tags が並列で適用されていたため、タグを2つともつけた場合に2つとも適用されてしまっていました。これを if_wm1_in_tags と elif_wm2_in_tags のように、else if で条件指定したいことはあるでしょう。

残念ながら、現時点では else if のような機能は用意されていません。(if_else と if_wm2_in_tags を組み合わせるのもだめです。)そのため、条件の指定を工夫する必要があります。

else if みたいなことを実現する例

例えば、以下のような条件を指定したいとします。

  • wm0 タグがあれば、何もしない
  • それ以外で、wm1 タグがあれば、黒文字のウォーターマーク
  • それ以外で、wm2 タグがあれば、白文字のウォーターマーク
  • それ以外であれば、黄文字のウォーターマーク

これは、次のように条件を整理して、パラメータ指定することで実現可能です。

  • wm0 タグがあれば、何もしない(何かは指定する必要があるため、a_0 や o_100 を指定する)
  • wm1 タグがあり、wm0 タグがなければ、黒文字のウォーターマーク
  • wm2 タグがあり、wm0 タグがなく、 wm1 タグもなければ、白文字のウォーターマーク
  • wm0 タグがなく、wm1 タグがなく、 wm2 タグもなければ、黄文字のウォーターマーク
https://res.cloudinary.com/CLOUD_NAME/image/upload
  /w_330
  /if_!wm0!_in_tags,o_100
  /if_!wm1!_in_tags_and_!wm0!_nin_tags,a_20,co_black,fl_relative,l_text:verdana_30_bold:classmethod,o_40,w_0.6
  /if_!wm2!_in_tags_and_!wm0!_nin_tags_and_!wm1!_nin_tags,a_20,co_white,fl_relative,l_text:verdana_30_bold:classmethod,o_40,w_0.6
  /if_!wm0!_nin_tags_and_!wm1!_nin_tags_and_!wm2!_nin_tags,a_20,co_red,fl_relative,l_text:verdana_30_bold:classmethod,o_40,w_0.6
  /v1/path/to/file.jpg

Cloudinary - 条件分岐の変換

いずれのタグも含まない画像

"条件"が変わったら

上記のようにタグで判定して異なる処理を適用する場合、画像に付与するタグを更新して、適用させる処理も更新させたいこともあるでしょう。

■ コンソールの場合

Cloudinaryのほとんどのコンソール上での変更操作は、キャッシュ無効化が含まれているようです。コンソール上でタグを追加・削除した場合は、そのアセットの変換URLのキャッシュは無効化されるため、その後(※)のURLアクセス時に改めて変換が適用され、更新した条件に基づいて判定されます。

※ 完全にCDN伝播させるため、キャッシュ無効化には、数分(最大1時間)かかります。

■ API の場合

API でタグを更新する場合は、Tags メソッドでタグの追加や削除ができます。1つまたは複数のアセットに適用可能です。

replace_tag では現在付与されているタグを考慮することなく、既存のを上書きして新しいタグ設定を指定することができます。以下の例では、既存でwm3が付与されている"berlin-dresden"と既にwm2が付与されている"tor-light"に対して、wm2のみ付与するようタグ設定をまとめて更新します。

cloudinary.uploader.replace_tag(
  "wm2", ["insta/berlin-dresden", "insta/tor-light"])

Explicit メソッドでもタグ設定を変更することができ、こちらは1つのアセットに対し複数のタグを付与したい場合に便利です。次の例では、既存で付与されているwm1は除去され、wm0とwm2が付与されます。上記の条件分岐変換を適用していると、黒文字のウォーターマークが適用されていたのが、更新後は何もウォーターマークがなくなります。

res = cloudinary.uploader.explicit(
  "insta/hamburg", type = "upload", tags = ["wm0", "wm2"], invalidate = True)

◆ 英語ドキュメント: Upload API - Explicit methodUpload API - Tags method

以上です。ぜひ Cloudinary の条件分岐変換を試してみてください!


クラスメソッドはCloudinaryのパートナーとして導入のお手伝いをさせていただいています。お気軽にこちらからお問い合わせください。こちらから無料でもサインアップいただけます。