Go言語でOG:image用の画像を生成するAPIを作成してみた

# はじめに
おそらく、やい、確実にNode.js系のライブラリを使って作成した方が簡単だと思います
Goでももっと簡単に直感的に作る方法はあると思いますが

# リポジトリ

https://github.com/chihiros/example-og-image-api

# まず、はじめにFigmaでレイアウトを決める

1. 1200x630の画像を作成します（なんか1200x630が推奨サイズらしいから）
1. ほか色々とレイアウトを決めましょう
1. フォントの種類・文字の太さ・文字を折り返す長さを決める
    1. 今回は910px以上の文字サイズになったら折り返すようにしました
    1. タイトル:[`　Noto Sans Japanese - Midumu`](https://fonts.google.com/noto/specimen/Noto+Sans+JP) を使っています
    1. ユーザー名：[`　Noto Sans Japanese - Regular`](https://fonts.google.com/noto/specimen/Noto+Sans+JP) を使っています

↓ できたものがこちらになります

<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="800" height="450" src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FOmwng4KV8gNTvd7pK5jwV4%2FUntitled%3Ftype%3Ddesign%26node-id%3D0%253A1%26mode%3Ddesign%26t%3D11IfqMZVanKVpziK-1" allowfullscreen></iframe>

# FigmaのデザインをGoで再現する
### Figma上でCSSの情報を見ることができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/38556482-cdf1-1adb-047a-1441193102d0.png)

### 背景色の情報をGoで表現する
これがFigmaから取得した背景色の色です。こちらは透明色（Alpha）を使っていますが、RGBAよりRGB表現の画像の方が使いやすいのでRGBAをRGBに変換しましょう

> background: linear-gradient(105deg, #FFC5C1 0%, rgba(217, 140, 218, 0.29) 25%, rgba(255, 246, 167, 0.68) 69.43%, rgba(122, 239, 255, 0.37) 100%);

Alphaを使っている場合は、こう言ったツールを使いましょう

https://www.oh-benri-tools.com/tools/color/rgb-to-rgba


```go
// 1200x630の画像を生成
width := 1200
height := 630
dc := gg.NewContext(width, height)

// 左上から右下に向かってグラデーション
grad := gg.NewLinearGradient(0, 0, float64(width), float64(height))
grad.AddColorStop(0, color.RGBA{255, 197, 193, 255})
grad.AddColorStop(0.25, color.RGBA{244, 222, 244, 255})
grad.AddColorStop(0.6943, color.RGBA{255, 249, 195, 255})
grad.AddColorStop(1, color.RGBA{206, 249, 255, 255})
dc.SetFillStyle(grad)

// 画像全体の矩形を描画してグラデーションを適用
dc.DrawRectangle(0, 0, float64(width), float64(height))
dc.Fill()
```

このコードでこのようなグラデーションの画像の生成が出来ます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/2caed312-ca8a-0a81-cbd9-12533a48ed9c.png)

### グラデーションの上に白い図形を追加する
Figmaから取得したCSSをもとにPaddingの設定をやりましょう
```go
// 図形のサイズと位置を計算
rectWidth := width - 2*43
rectHeight := height - 2*41
rectX := 43
rectY := 41

// 背景色を設定
dc.SetColor(color.RGBA{255, 255, 255, 255})
dc.DrawRoundedRectangle(float64(rectX), float64(rectY), float64(rectWidth), float64(rectHeight), 16)
dc.Fill()
```

白い図形が追加されました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/67dcd740-401a-a398-b839-a7f464f18be0.png)

### タイトルを表示する
私はバイナリで動かす前提で作っていますので、embedを使ってフォントを埋め込んでいます
```go
//go:embed embed/NotoSansJP-Medium.otf
var fontTitle []byte
/* 〜〜〜〜〜〜〜〜 中略 〜〜〜〜〜〜〜〜 */
// フォントを読み込む
fontFace, err := opentype.Parse(fontTitle)
if err != nil {
    http.Error(w, "Failed to parse font", http.StatusInternalServerError)
    return
}

face, err := opentype.NewFace(fontFace, &opentype.FaceOptions{
    Size: 64,
    DPI:  72,
})

if err != nil {
    http.Error(w, "Failed to create font face", http.StatusInternalServerError)
    return
}
dc.SetFontFace(face)

// 文字を挿入
dc.SetRGB(0, 0, 0) // 文字色を黒に設定

maxWidth := 910.0
title := "Go言語でOG:imageを作成してみる！！"
formatTitle := ""

tmp := 0.0
for _, word := range title {
    fw, _ := dc.MeasureString(string(word))
    if tmp+fw > maxWidth {
        formatTitle += "\n"
        tmp = 0.0
    }

    formatTitle += string(word)
    tmp += fw
}

x := 145.0
y := 175.0
for _, line := range strings.Split(formatTitle, "\n") {
    dc.DrawString(line, x, y)
    y += 82
}
```

このようにフォントが追加されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/b1f72764-97ca-805e-19fd-b4203d1b4cb6.png)

### ユーザー名を追加
上の一緒のことをやるだけなので(ry

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/a6b736ca-3b91-b7cc-6b64-32da4026de9c.png)

### サイトなり、好きロゴを入れる（それっぽくなる）

```go
//go:embed embed/logo.png
var logo []byte
/* 〜〜〜〜〜〜〜〜 中略 〜〜〜〜〜〜〜〜 */
// サイトのロゴを挿入
logoImg, _, err := image.Decode(strings.NewReader(string(logo)))
if err != nil {
    http.Error(w, "Failed to decode logo image", http.StatusInternalServerError)
    return
}

// ロゴのサイズを変更
resizedLogoImg := resize.Resize(0, 150, logoImg, resize.Lanczos3)

// ロゴを挿入
dc.DrawImage(resizedLogoImg, 800, 430)
```

Figmaで作ったやつと同じようなやつができました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/cf8fff2c-cc8e-77b8-47bf-cc49d16d24cb.png)

大体、同じものができました！！（発色が少し違う）
| Figmaで作成したやつ | Goで生成したやつ |
| :---: | :---: |
| ![Frame 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/e52efbad-ea57-125b-26b4-39a2d2094689.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/cf8fff2c-cc8e-77b8-47bf-cc49d16d24cb.png) |

# 最後に
最初でも言ってますが、Goでやることでは無いと思います。
私は趣味でWebサイト作ってまして、OG:imageに対応するためにReactで作っているWebサイトをNext.jsで書き直しています。その流れでOGイメージもNext.jsで作ろうとしたんですが、~~作るのが難しくて~~ 私がフロント素人なものでGoに逃げました。

私の𝕏（Twitter）はこちらです。エンジニアのフォロワーさんが少ないので、フォローしていただけたら嬉しいです

https://twitter.com/com_index