Nuxt+Firebaseで開発してるサービスのOGP画像を改善しようと、
いろいろ試してみたときの備忘録。
OGP画像の生成はクライアント側とサーバ側かがあるが、
Firestoreの変更に合わせて生成したいので、
Cloud Function上で利用できる方法を考えてた。
結果的に、
という構成になった。その試行錯誤の備忘録です。
背景画像+本の画像+文字みたいなOGP画像にしたい。
あと、座標の指定はめんどくさいので、楽な方法を探してみた。
SVGだとCSSも使えて、ブラウザ上で書くにできるので良さそう。
(と思ったけど、結果、だめだった...)
試したのは以下の4パターン。
SVG+sharpで試した感じ。
node-canvasはおまけな感じ程度。
内部で利用しているSVGライブラリ自体で未対応っぽいので、
SVGのstyleや外部URLの画像、カスタムフォントなどは、
ブラウザ上以外の画像生成ではまだ未対応っぽい。
ほかにも、CloudFunction上でpuppeteerを使えるようだけど、
メモリをすごい使うっぽい記事を見てしまい、まだためしてない。。
以下試したコード。
import sharp from "sharp";
await sharp("./input.svg")
.png()
.toFile("./output.png");
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0 0 1200 630" width="1200" height="630">
<style>
@import url("https://fonts.googleapis.com/css?family=Noto+Sans+JP:500&display=swap&subset=japanese");
.contents {
display: flex;
justify-content: center;
align-items: flex-end;
width: 1200px;
height: 630px;
position: relative;
}
.book {
height: calc(100% - 100px);
}
.text-contents {
position: absolute;
left: 0;
right: 0;
bottom: 58px;
width: 1200px;
background-color: rgba(0, 0, 0, 0.6);
font-family: "Noto Sans JP", sans-serif;
color: white;
padding-bottom: 8px;
text-align: center;
}
.text-label {
font-size: 60px;
font-weight: 500;
padding-left: 0.5em;
}
.title-label {
font-size: 28px;
font-weight: 500;
padding-top: 0.2em;
}
</style>
<image xlink:href="https://.../background.png" width="1200" height="630" />
<foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" width="1200" height="630">
<div class="contents">
<img class="book" src="https://.../thumbnail.png" />
<div class="text-contents">
<div class="text-label">
<span>読みます!!</span>
</div>
<div class="title-label">
<span>リーダブルコード</span>
</div>
<div class="title-label">
<span>ダスティン・ボズウェル/トレバー・フォシェ</span>
</div>
</div>
</div>
</foreignObject>
</svg>
import axios from "axios";
import sharp from "sharp";
// 埋め込む画像のURL
const bookURL = "https://.../thumbnail.png";
const bookBuffer = await axios.get(bookURL, { responseType: "arraybuffer" });
// URLから取得した画像を加工(リサイズ)
const bookImage = await sharp(bookBuffer.data)
.resize(520, 454, { position: "top" })
.toBuffer();
// sharpで結合
await sharp("./background.png") // 背景画像を読み込み
.composite([
{ input: bookImage, gravity: "south" }, 本の画像を書き出し
{ input: "./input.svg" } // SVGの書き出し
])
.png()
.toFile(tempFile);
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0 0 1200 630" width="1200" height="630">
<defs>
<!-- Fontを外部URLで指定 -->
<font-face font-family="Noto Sans JP">
<font-face-src>
<font-face-uri xlink:href="https://fonts.googleapis.com/css?family=Noto+Sans+JP:400,700|Roboto:400,700&display=swap&subset=japanese" />
</font-face-src>
</font-face>
<!-- フォントをローカルファイルで指定 -->
<font-face font-family="Noto Sans JP" font-weight="500">
<font-face-src>
<font-face-uri xlink:href="./font/NotoSansJP-Medium.otf">
<font-face-format string="opentype"/>
</font-face-uri>
</font-face-src>
</font-face>
<font-face font-family="Noto Sans JP" font-weight="700">
<font-face-src>
<font-face-uri xlink:href="./font/NotoSansJP-Bold.otf">
<font-face-format string="opentype"/>
</font-face-uri>
</font-face-src>
</font-face>
<!-- ローカルファイルを@font-faceで指定 -->
<style type="text/css">
@font-face {
font-family: 'Noto Sans JP';
font-style: normal;
font-weight: 500;
src: url('./font/NotoSansJP-Medium.otf') format("opentype");
}
@font-face {
font-family: 'Noto Sans JP';
font-style: normal;
font-weight: 700;
src: url('./font/NotoSansJP-Bold.otf') format("opentype");
}
</style>
</defs>
<rect x="0" y="530" width="1200" height="100" fill="#000000" fill-opacity="0.6" />
<text x="610" y="156" font-size="60" fill="#FFFFFF" text-anchor="middle">
<tspan font-weight="700">読みます!!</tspan>
</text>
<text x="600" y="574" font-size="28" fill="#FFFFFF" text-anchor="middle">
<tspan font-weight="700">リーダブルコード</tspan>
</text>
<text x="600" y="610" font-size="24" fill="#FFFFFF" text-anchor="middle">
<tspan font-weight="500">ダスティン・ボズウェル/トレバー・フォシェ</tspan>
</text>
</svg>
積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!
積読ハウマッチは、Nuxt.js+Firebaseで開発してます!
もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ
要望・感想・アドバイスなどあれば、
公式アカウント(@MemoryLoverz)や開発者(@kira_puka)まで♪
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント