作ったもの:日付・開始時刻・終了時刻・タイトルを大きく書いたPNG
こんにちは。辛子屋 芥子と申します。
「配信 ふりかえり 画像 自動 作成」と探して、ここへ来てくださったのだと思います。配信が終わったあとに、「今日は何時から何時まで、何という配信をしたか」を一枚にまとめた画像を作るものを書きました。今日はその話を書きます。
出来上がりは、1920 × 1080 の PNG です。大きな文字で書いてあるのは、次の4つです。
- 配信タイトル
- 配信日
- 開始時刻
- 終了時刻
画面の見た目は、作る前に自分で決めました。背景は濃い紺。左上に辛子色の短い線を一本だけ引きます。その下に「配信タイトル:」と書いて、そこから大きな文字で題を置きます。真ん中あたりに細い線を一本引いて、下の段に「配信日:」「開始時刻:」「終了時刻:」を並べます。色を使うのは、辛子色の線と、背景と、文字の濃さの違いだけにしました。余白はたっぷり取っています。配信の絵の上に重ねるのではなく、これ一枚で見せる絵にしたかったからです。
作ったのは、HTML と JavaScript の一枚のファイルです。ブラウザがもともと持っている canvas という仕組みで絵を描いています。ですので、追加で読み込むライブラリはありません。ファイルをひとつ作って、その中に全部を貼れば、それで動きます。
4つを聞いて、それを大きく書いた画像を出す。短いものです。入力する所も4つだけです。
ひとつだけ、正直に書いておきます。出来上がりの PNG そのものは、この記事に置いていません。撮っていないからです。代わりに、OBS の中で動かした時の写真を2枚、あとの方に置きました。実際に映っている絵は、そちらでごらんください。
置くコード:質問に答えるとPNGが保存されるまで
そのまま置けるように、一本で載せます。ライブラリを読み込む行は、このコードにはありません。ブラウザにもともと入っている canvas を使っているからです。その分、ファイルをひとつ作るだけで済みます。
<!DOCTYPE html>
<html lang='ja'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>配信のふりかえり画像を作る</title>
<style>
*{box-sizing:border-box;}
body{
margin:0;
padding:32px 20px 80px;
background:#0C0F16;
color:#F2F6FB;
font-family:'Hiragino Sans','Yu Gothic','Noto Sans JP','Meiryo',sans-serif;
line-height:1.7;
}
.wrap{max-width:1000px;margin:0 auto;}
h1{font-size:22px;margin:0 0 10px;}
.lead{margin:0 0 32px;font-size:14px;color:#8FA3BF;}
.fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px 24px;}
.wide{grid-column:1 / -1;}
label{display:block;font-size:13px;color:#8FA3BF;margin-bottom:8px;}
input{
width:100%;padding:12px 14px;font-size:16px;font-family:inherit;
color:#F2F6FB;background:#1A2030;
border:1px solid #2A3346;border-radius:6px;
}
input:focus{outline:2px solid #E8B93B;outline-offset:1px;}
.buttons{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:32px 0 10px;}
button{font-family:inherit;font-size:15px;font-weight:700;padding:12px 22px;border:0;border-radius:6px;cursor:pointer;}
.primary{background:#E8B93B;color:#12161F;}
.ghost{background:transparent;color:#F2F6FB;border:1px solid #2A3346;}
.message{font-size:13px;color:#8FA3BF;min-height:1.7em;margin:0 0 20px;}
.message.alert{color:#F0A08A;}
.preview{border:1px solid #2A3346;border-radius:8px;overflow:hidden;background:#12161F;}
canvas{display:block;width:100%;height:auto;}
@media (max-width:640px){
.fields{grid-template-columns:1fr;}
}
</style>
</head>
<body>
<div class='wrap'>
<h1>配信のふりかえり画像を作る</h1>
<p class='lead'>はじめは見本の内容が入っています。書きかえると、下の絵がすぐ変わります。できあがりは 1920 × 1080 の PNG です。</p>
<div class='fields'><div class='wide'><label for='title'>配信タイトル</label><input id='title' type='text' value='はじめての雑談配信'></div><div><label for='date'>配信日</label><input id='date' type='date'></div><div><label for='start'>開始時刻</label><input id='start' type='time' value='21:00'></div><div><label for='end'>終了時刻</label><input id='end' type='time' value='22:30'></div></div>
<div class='buttons'><button id='save' class='primary' type='button'>PNG 画像を保存する</button><button id='sample' class='ghost' type='button'>見本の内容に戻す</button></div><p id='message' class='message'>PNG 画像を保存するを押すと、ファイルがダウンロードされます。</p>
<div class='preview'><canvas id='board' width='1920' height='1080'></canvas></div></div>
<script>// 画面の大きさと余白。ここを決めてから中身を置いていきます。const WIDTH = 1920;const HEIGHT = 1080;const PAD = 140;
const COLOR = {background: '#12161F',value: '#F2F6FB',label: '#8FA3BF',rule: '#2A3346',accent: '#E8B93B'};
const FONT_JA = `'Hiragino Sans','Yu Gothic','Noto Sans JP','Meiryo',sans-serif`;const FONT_NUMBER = `'SFMono-Regular','Consolas','DejaVu Sans Mono','Menlo',monospace`;
const TITLE_SIZES = [96, 84, 72, 64];const TITLE_LINE_HEIGHT = 1.34;const TITLE_MAX_LINES = 3;
const canvas = document.getElementById('board');const ctx = canvas.getContext('2d');const titleInput = document.getElementById('title');const dateInput = document.getElementById('date');const startInput = document.getElementById('start');const endInput = document.getElementById('end');const message = document.getElementById('message');
// 配信日の入力(2026-09-21)を、画像に出す言葉に直します。function dateToText(value){const parts = value.split('-');const year = Number(parts[0]);const month = Number(parts[1]);const day = Number(parts[2]);const weekday = ['日','月','火','水','木','金','土'][new Date(year, month - 1, day).getDay()];return year + '年' + month + '月' + day + '日(' + weekday + ')';}
function todayValue(){const now = new Date();const month = String(now.getMonth() + 1).padStart(2, '0');const day = String(now.getDate()).padStart(2, '0');return now.getFullYear() + '-' + month + '-' + day;}
// 日本語は語の切れ目が無いので、一文字ずつ測って折り返します。function wrapText(text, maxWidth){const lines = [];let line = '';for (const char of text){const next = line + char;if (line !== '' && ctx.measureText(next).width > maxWidth){lines.push(line);line = char === ' ' ? '' : char;} else {line = next;}}lines.push(line);return lines;}
function drawBoard(data){// 背景は透かさず塗ります。明るい映像の上でも暗い映像の上でも、// 文字の下に必ずこの濃い色が来るようにするためです。ctx.fillStyle = COLOR.background;ctx.fillRect(0, 0, WIDTH, HEIGHT);
ctx.textBaseline = 'top';
// 辛子色の細い線。ここだけ色を使います。ctx.fillStyle = COLOR.accent;ctx.fillRect(PAD, 118, 132, 6);
// 見出しと中身:配信タイトルctx.fillStyle = COLOR.label;ctx.font = '700 38px ' + FONT_JA;ctx.fillText('配信タイトル:', PAD, 160);
const maxWidth = WIDTH - PAD * 2;let titleSize = TITLE_SIZES[TITLE_SIZES.length - 1];let titleLines = null;for (const size of TITLE_SIZES){ctx.font = '700 ' + size + 'px ' + FONT_JA;const wrapped = wrapText(data.title, maxWidth);if (wrapped.length <= TITLE_MAX_LINES){titleSize = size;titleLines = wrapped;break;}}if (titleLines === null){ctx.font = '700 ' + titleSize + 'px ' + FONT_JA;titleLines = wrapText(data.title, maxWidth);}if (titleLines.length > TITLE_MAX_LINES){titleLines = titleLines.slice(0, TITLE_MAX_LINES);titleLines[TITLE_MAX_LINES - 1] = titleLines[TITLE_MAX_LINES - 1].slice(0, -1) + '…';}
ctx.fillStyle = COLOR.value;ctx.font = '700 ' + titleSize + 'px ' + FONT_JA;const titleLineHeight = Math.round(titleSize * TITLE_LINE_HEIGHT);titleLines.forEach(function(line, index){ctx.fillText(line, PAD, 232 + index * titleLineHeight);});
// 上下を分ける線ctx.fillStyle = COLOR.rule;ctx.fillRect(PAD, 760, WIDTH - PAD * 2, 2);
// 下の段:配信日・開始時刻・終了時刻const columns = [{ label: '配信日:', text: data.date, font: FONT_JA },{ label: '開始時刻:', text: data.start, font: FONT_NUMBER },{ label: '終了時刻:', text: data.end, font: FONT_NUMBER }];
const valueSize = 64;const widths = [];let totalWidth = 0;columns.forEach(function(column){ctx.font = '700 ' + valueSize + 'px ' + column.font;const width = ctx.measureText(column.text).width;widths.push(width);totalWidth += width;});
const gap = Math.max(80, ((WIDTH - PAD * 2) - totalWidth) / (columns.length - 1));let x = PAD;columns.forEach(function(column, index){ctx.fillStyle = COLOR.label;ctx.font = '700 36px ' + FONT_JA;ctx.fillText(column.label, x, 830);
ctx.fillStyle = COLOR.value;ctx.font = '700 ' + valueSize + 'px ' + column.font;ctx.fillText(column.text, x, 900);
x += widths[index] + gap;});}
function readInput(){const title = titleInput.value.trim();if (title === '') return { error: '配信タイトルを入れてください。' };if (dateInput.value === '') return { error: '配信日を入れてください。' };if (startInput.value === '') return { error: '開始時刻を入れてください。' };if (endInput.value === '') return { error: '終了時刻を入れてください。' };return {title: title,date: dateToText(dateInput.value),start: startInput.value.slice(0, 5),end: endInput.value.slice(0, 5)};}
function render(){const data = readInput();if (data.error){message.textContent = data.error;message.className = 'message alert';return null;}message.textContent = 'この絵で保存できます。';message.className = 'message';drawBoard(data);return data;}
function fillSample(){titleInput.value = 'はじめての雑談配信';dateInput.value = todayValue();startInput.value = '21:00';endInput.value = '22:30';}
document.getElementById('sample').addEventListener('click', function(){fillSample();render();});
document.getElementById('save').addEventListener('click', function(){if (render() === null) return;const fileName = '配信ふりかえり_' + dateInput.value + '.png';const link = document.createElement('a');link.download = fileName;link.href = canvas.toDataURL('image/png');link.click();message.textContent = fileName + ' の保存をはじめました。ブラウザのダウンロードをごらんください。';});
[titleInput, dateInput, startInput, endInput].forEach(function(input){input.addEventListener('input', render);});
fillSample();
render();
</script>
</body>
</html>
長いので、どこで何をしているかを短く書いておきます。
WIDTH/HEIGHT/PAD:絵の大きさと、周りの空き。これを先に決めてから、中身を置きました。COLOR:色です。背景・文字・見出し・線・辛子色の5つだけ。あとで色を変える時は、ここだけ見れば変えられます。dateToText:入力の「2026-09-21」を、「2026年9月21日(月)」という言葉に直します。曜日も入れています。wrapText:日本語は語の切れ目がないので、一文字ずつ幅を測って折り返します。drawBoard:ここが絵を描く所です。上から順に、背景、辛子色の線、題、仕切り線、下の段、と置いていきます。readInputとrender:4つを読んで、空の所があれば画面に知らせます。- 最後の所:
canvas.toDataURL('image/png')で画像にして、link.downloadでファイル名を付けて保存します。
動かす前に、読む人の側で用意するもの
読む方の側で用意するものです。順に書きます。
まず、パソコン。Windows でも Mac でも動きます。
次に、ブラウザ。Chrome、Edge、Firefox、Safari のどれか。canvas が使えるブラウザなら大丈夫です。特別なものは要りません。
それから、文字を打って保存できるもの。メモ帳や、テキストエディットなど、最初から入っているもので足ります。
日本語のフォント。ふつうは、もう入っています。Windows なら「游ゴシック」か「メイリオ」、Mac なら「ヒラギノ角ゴ」。コードでは、この順に探して、最初に見つかったものを使うように書いてあります。もし日本語が豆腐(□□□)になってしまうなら、Google が配っている「Noto Sans JP」を入れてください。取り方は Google Fonts のページ(https://fonts.google.com/noto)にあります。入れる場所は、お使いの OS の案内に従ってください。
配信の絵として出したい方は、OBS Studio。公式サイト(https://obsproject.com/)から無料で取れます。
ファイルの置き場所をひとつ決めてください。デスクトップでも、書類フォルダでも、自分で分かる所で大丈夫です。保存した PNG の行き先は、ブラウザのダウンロードフォルダです。
手順は、こうです。
- メモ帳などを開いて、新しいファイルを作ります。
- 上のコードを、そのまま貼ります。
- 「ふりかえり.html」という名前で保存します。この時、文字コードは UTF-8 を選んでください。選べない時は、種類を「すべてのファイル」にして、名前を「ふりかえり.html」にします。コードの中に UTF-8 と書いてあるので、ここを合わせると文字化けしません。
- 保存したファイルを、ブラウザの窓にドラッグします。または、ダブルクリックします。
- 上から4つ、配信タイトル・配信日・開始時刻・終了時刻を入れます。入れるそばから、下の絵が変わります。
- 「PNG 画像を保存する」を押します。
- ダウンロードフォルダに「配信ふりかえり_2026-09-21.png」のような名前で入っています。
わたくしが自分の目で確かめたのは、OBS のブラウザソースに読み込んだ所までです。ふつうのブラウザで開いた時も同じ絵になる作りですが、そこは確かめていません。
お借りしたものと、その出どころ
お借りしたものを、名前と置き場所と一緒に並べます。
- canvas(絵を描く仕組み)、HTML、CSS、JavaScript:HTML の決まりを作っている WHATWG の仕様です。読み方の説明は MDN の Canvas API のページ(https://developer.mozilla.org/ja/docs/Web/API/Canvas_API)にあります。
- ブラウザ:Chrome(Google 公式 https://www.google.com/chrome/)、Edge(Microsoft 公式 https://www.microsoft.com/edge)、Firefox(Mozilla 公式 https://www.mozilla.org/ja/firefox/new/)、Safari(Apple 公式 https://www.apple.com/jp/safari/)。canvas はこのどれにも入っています。
- OBS Studio:OBS Project が作っている配信のソフトです。公式サイトは https://obsproject.com/ です。この中の「ブラウザソース」という機能で、HTML を配信の絵として出せます。
- 書体(画像の中で使う名前です。実際に使われるのは、読む方のパソコンに入っているものです)
- Noto Sans JP:Google(と Adobe)が作った書体で、SIL Open Font License 1.1 で配られています。置き場所は https://fonts.google.com/noto 、作っている方のリポジトリは https://github.com/notofonts/noto-cjk です。
- Hiragino Sans(ヒラギノ角ゴ)、Menlo、SFMono-Regular:Apple の書体です。
- Yu Gothic(游ゴシック)、Meiryo(メイリオ)、Consolas:Microsoft の書体です。
- DejaVu Sans Mono:フリーで配られている書体です。配布ページの場所をわたくしが確かめていないので、名前だけ挙げます。
- 自分で書いた所:この記事に載せた HTML・CSS・JavaScript は、わたくしが書きました。線引きをすると、ファイルの中身はここからここまで、ぜんぶ自分で書いたものです。お借りしたのは、ブラウザに入っている canvas の仕組みと、パソコンに入っている書体だけです。
OBS の中で動かしてみた画面
OBS に読み込んで、映るところまでやりました。手順はこうです。
- OBS を開きます。
- 「ソース」の欄の + を押して、「ブラウザ」を選びます。名前は何でも大丈夫です。
- 「ローカルファイル」に印を付けて、保存した HTML を選びます。
- 幅と高さを、1920 と 1080 にします。作った絵と同じ数です。
- 閉じると、絵が出ます。


わたくしが確かめたのは、ここまでです。読んでくださった方の手元でも同じように出るかは、環境が違いますので、やってみないと分かりません。
確かめていないことも、並べておきます。
- 実際の配信で使ったこと。配信の終わりに出す使い方をご案内しましたが、わたくしは配信をしていないので、そこから先は分かりません。
- 「PNG 画像を保存する」のボタンを、OBS の中で押したこと。ブラウザソースは配信の絵を出すためのもので、押して操作する所は、わたくしは試していません。保存は、ふつうのブラウザで開いて行うものだと思ってください。
- 保存したふりかえり画像をポストした時の見え方。
- ほかのブラウザや、スマホでの見え方。
- とても長いタイトルを入れた時の折り返し。3行に収まらない分は「…」にしていますが、そこまでは試していません。
こういう使い方はいかがですか
いくつか並べます。どれも、4つを入れて PNG を保存する、という同じ所から始まります。
ひとつめ。ふりかえり画像をそのままポストする使い方。配信が終わってから、X などに添える絵にできます。文章を書かなくても、日付と時刻と題が残ります。
ふたつめ。配信のサムネイルにする使い方。配信タイトルをその配信の題に、配信日をその日にします。始める前に作っておけば、同じ絵が終わったあとのふりかえりにも使えます。
みっつめ。配信の終わりに出す使い方。OBS のブラウザソースとして置いておいて、終わりのあいさつの時に映します。
わたくしが良いと思うのは、ひとつめとみっつめです。配信が終わったあとにまとめるのは、少し面倒で、後回しになりがちです。4つ入れるだけで一枚出るなら、その面倒が少し軽くなるのではないかと思います。
こう広げられます:手を入れる所
どこを触ると何が変わるかを書いておきます。コードの中の名前で書きます。
- 文字の大きさ:題は
TITLE_SIZES(96 → 84 → 72 → 64 の順に試して、3行に収まる大きさを選びます)。下の段の時刻と日付はvalueSize(64)。「配信タイトル:」などの見出しは 38px、「配信日:」などの見出しは 36px の所です。 - 行間:
TITLE_LINE_HEIGHT(1.34)。大きくすると、題の行と行が離れます。 - 余白:
PAD(140)。絵の周りの空きです。ほかに、118(辛子色の線の高さ)、160(「配信タイトル:」の位置)、232(題の始まり)、760(仕切り線の位置)、830 と 900(下の段の見出しと中身の位置)。 - 色:
COLORの中のbackground(背景)、value(文字)、label(見出し)、rule(仕切り線)、accent(辛子色の線)。辛子色をやめたい時は、accentを変えます。 - 画像の寸法:
WIDTHとHEIGHT。変えたら、canvas のwidth='1920' height='1080'も同じ数に変えてください。OBS のブラウザソースの幅と高さも、同じ数にします。 - 項目の数:
columnsという配列です。ここに一つ足すと、下の段が一つ増えます。足した時は、x の計算も一緒に見てください。入力欄を増やす時は、HTML のinputとreadInputの所を合わせます。 - 折り返す行数:
TITLE_MAX_LINES(3)。変えると、長い題の時の収まりが変わります。
触ると何が変わるかは、その都度、下の絵ですぐ見えます。入れながら決められるのが、この形にして良かった所だと思っています。
さいごに
配信のふりかえり画像を、4つ入れるだけで出すものを作りました。質問に答えると PNG が保存されるまでを、この記事に一本で置いています。
わたくしが確かめたのは、OBS のブラウザソースに読み込んで、絵が出るところまでです。配信で使った話は書けません。していないからです。
もし使ってみて合わない所があれば、「手を入れる所」から直せます。色を自分の好きな色に変えるのも、楽しいと思います。
辛子屋 芥子



コメント