node.js에서는 블로그 스타일의 아이 캐치 이미지를 동적으로 생성합니다.
요즘 블로그 기사에 한하지 않고 다양한 서비스에서 콘텐츠를 SNS 공유할 때 어떻게 눈에 띄게 할까라는 부분인 아이 캐치의 OGP 이미지 설정의 중요성은 말할 필요도 없다고 생각합니다.
자신도 운영하고 있는 서비스로 동적으로 OGP를 작성하는 이른바 「OGP예」를 잘 하고 있습니다만, 향후 점점 필요성이 높아질 것으로 생각해, OGP예용의 두드려대로 하는 처리 템플릿을 만들었습니다.
아티팩트 샘플
소스 코드
const fs = require("fs");
const { createCanvas } = require('canvas')
const base64 = require('urlsafe-base64');
// canvasの横幅
let canvasWidth = 1200;
// canvasの縦幅
let canvasHeight = 630;
let canvas;
let ctx;
// タイトル部分の文字スタイル
const titleFontStyle = {
font: 'bold 73px "Noto Sans CJK JP"',
lineHeight: 80,
color: '#333333'
};
// 本文部分の文字スタイル
const bodyFontStyle = {
font: '30px "Noto Sans CJK JP"',
lineHeight: 38,
color: '#666666'
};
// 画像内側余白
let padding = 80;
// 背景色
let backgroundColor = "#d3ffb1";
let generate = (title, body, fileName) => {
// 空白のcanvasを作成
canvas = createCanvas(canvasWidth, canvasHeight)
// コンテキスト取得
ctx = canvas.getContext('2d')
// -----
// タイトル描画
// -----
// 行長さ
let lineWidth = canvasWidth - (padding * 2);
// フォント設定
ctx.font = titleFontStyle.font;
// 行数の割り出し
let titleLines = splitByMeasureWidth(title, lineWidth, ctx);
let titleLineCnt = titleLines.length;
// タイトル分の高さ
let titleHeight = titleLines.length * titleFontStyle.lineHeight;
// -----
// 本文部分描画
// -----
let titleMargin = 40;
// フォント設定
ctx.font = bodyFontStyle.font;
// 行数の割り出し
let bodyLines = splitByMeasureWidth(body, lineWidth, ctx);
let bodyLineCnt = bodyLines.length;
// 本文分の高さ
let bodyHeight = bodyLines.length * bodyFontStyle.lineHeight;
// 行高さと余白が最小高さ(630)を上回る場合はカンバスをリサイズする
let contentHeight = titleHeight + titleMargin + bodyHeight + (padding * 2);
if (canvasHeight < contentHeight) {
canvasHeight = contentHeight
canvas = createCanvas(canvasWidth, contentHeight)
ctx = canvas.getContext('2d')
}
// 取り敢えず背景色をつける
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvasWidth, canvasHeight)
// 文字描画のベースラインを設定
ctx.textBaseline = 'top';
// タイトルを描画
ctx.fillStyle = titleFontStyle.color;
ctx.font = titleFontStyle.font;
for (let index = 0; index < titleLineCnt; index++) {
const element = titleLines[index];
ctx.fillText(element, padding, padding + (titleFontStyle.lineHeight * index))
}
// 本文を描画
ctx.fillStyle = bodyFontStyle.color;
ctx.font = bodyFontStyle.font;
for (let index = 0; index < bodyLineCnt; index++) {
const element = bodyLines[index];
// タイトル分の高さと余白を加算する
ctx.fillText(element, padding, padding + (titleHeight + titleMargin) + (bodyFontStyle.lineHeight * index))
}
let b64 = canvas.toDataURL().split(',');
let img = base64.decode(b64[1]);
// ファイル保存
fs.writeFile(fileName, img, function (err) {
console.log(err);
});
}
function splitByMeasureWidth(str, maxWidth, context) {
// サロゲートペアを考慮した文字分割
let chars = Array.from(str);
let line = '';
let lines = [];
for (let index = 0; index < chars.length; index++) {
if (maxWidth <= context.measureText(line + chars[index]).width) {
lines.push(line);
line = chars[index];
}
else {
line += chars[index];
}
}
lines.push(line);
return lines;
}
module.exports = {
generate: generate
};
작동에 필요한 리소스
처리 라이브러리(node-canvas)
htps : // 기주 b. 코 m / 오토 마치 c / 그래서 칸 ゔ
이미지를 만들려면 node-canvas을 사용합니다.
설치 및 컴파일에 필요한 리소스를 설정하는 방법에 대해서는 해당 라이브러리의 Readme를 참조하여 환경에 맞게 준비하십시오.
글꼴
이번에는 Noto 글꼴을 사용하고 운영 환경에 설치되어 있다고 가정합니다.
동적으로 이미지를 만들 때 글꼴에 따라 사용 라이센스가 다를 수 있으므로주의가 필요합니다.
사용법
var ogpGenerator = require('./ogpGenerator');
ogpGenerator.generate(
'こういう画像が動的に作成できます。',
'そのころわたくしは、モリーオ市の博物局に勤めて居りました。十八等官でしたから役所のなかでも、ずうっと下の方でしたし俸給ほうきゅうもほんのわずかでしたが、受持ちが標本の採集や整理で生れ付き好きなことでしたから、わたくしは毎日ずいぶん愉快にはたらきました。',
'./YOUR_FILE_NAME.jpg'
);
배경에 이미지를 붙이거나, 개행 코드에 대응하거나 같은 것은 필요에 따라 적절히 부디.
Reference
이 문제에 관하여(node.js에서는 블로그 스타일의 아이 캐치 이미지를 동적으로 생성합니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/ampersand/items/805e75b5a54797923885
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
const fs = require("fs");
const { createCanvas } = require('canvas')
const base64 = require('urlsafe-base64');
// canvasの横幅
let canvasWidth = 1200;
// canvasの縦幅
let canvasHeight = 630;
let canvas;
let ctx;
// タイトル部分の文字スタイル
const titleFontStyle = {
font: 'bold 73px "Noto Sans CJK JP"',
lineHeight: 80,
color: '#333333'
};
// 本文部分の文字スタイル
const bodyFontStyle = {
font: '30px "Noto Sans CJK JP"',
lineHeight: 38,
color: '#666666'
};
// 画像内側余白
let padding = 80;
// 背景色
let backgroundColor = "#d3ffb1";
let generate = (title, body, fileName) => {
// 空白のcanvasを作成
canvas = createCanvas(canvasWidth, canvasHeight)
// コンテキスト取得
ctx = canvas.getContext('2d')
// -----
// タイトル描画
// -----
// 行長さ
let lineWidth = canvasWidth - (padding * 2);
// フォント設定
ctx.font = titleFontStyle.font;
// 行数の割り出し
let titleLines = splitByMeasureWidth(title, lineWidth, ctx);
let titleLineCnt = titleLines.length;
// タイトル分の高さ
let titleHeight = titleLines.length * titleFontStyle.lineHeight;
// -----
// 本文部分描画
// -----
let titleMargin = 40;
// フォント設定
ctx.font = bodyFontStyle.font;
// 行数の割り出し
let bodyLines = splitByMeasureWidth(body, lineWidth, ctx);
let bodyLineCnt = bodyLines.length;
// 本文分の高さ
let bodyHeight = bodyLines.length * bodyFontStyle.lineHeight;
// 行高さと余白が最小高さ(630)を上回る場合はカンバスをリサイズする
let contentHeight = titleHeight + titleMargin + bodyHeight + (padding * 2);
if (canvasHeight < contentHeight) {
canvasHeight = contentHeight
canvas = createCanvas(canvasWidth, contentHeight)
ctx = canvas.getContext('2d')
}
// 取り敢えず背景色をつける
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvasWidth, canvasHeight)
// 文字描画のベースラインを設定
ctx.textBaseline = 'top';
// タイトルを描画
ctx.fillStyle = titleFontStyle.color;
ctx.font = titleFontStyle.font;
for (let index = 0; index < titleLineCnt; index++) {
const element = titleLines[index];
ctx.fillText(element, padding, padding + (titleFontStyle.lineHeight * index))
}
// 本文を描画
ctx.fillStyle = bodyFontStyle.color;
ctx.font = bodyFontStyle.font;
for (let index = 0; index < bodyLineCnt; index++) {
const element = bodyLines[index];
// タイトル分の高さと余白を加算する
ctx.fillText(element, padding, padding + (titleHeight + titleMargin) + (bodyFontStyle.lineHeight * index))
}
let b64 = canvas.toDataURL().split(',');
let img = base64.decode(b64[1]);
// ファイル保存
fs.writeFile(fileName, img, function (err) {
console.log(err);
});
}
function splitByMeasureWidth(str, maxWidth, context) {
// サロゲートペアを考慮した文字分割
let chars = Array.from(str);
let line = '';
let lines = [];
for (let index = 0; index < chars.length; index++) {
if (maxWidth <= context.measureText(line + chars[index]).width) {
lines.push(line);
line = chars[index];
}
else {
line += chars[index];
}
}
lines.push(line);
return lines;
}
module.exports = {
generate: generate
};
var ogpGenerator = require('./ogpGenerator');
ogpGenerator.generate(
'こういう画像が動的に作成できます。',
'そのころわたくしは、モリーオ市の博物局に勤めて居りました。十八等官でしたから役所のなかでも、ずうっと下の方でしたし俸給ほうきゅうもほんのわずかでしたが、受持ちが標本の採集や整理で生れ付き好きなことでしたから、わたくしは毎日ずいぶん愉快にはたらきました。',
'./YOUR_FILE_NAME.jpg'
);
Reference
이 문제에 관하여(node.js에서는 블로그 스타일의 아이 캐치 이미지를 동적으로 생성합니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/ampersand/items/805e75b5a54797923885텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)