0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Seedream 5.0 Pro AI Generatorを無料で試す:Node.jsでOGP画像を安定化

0
Posted at

Seedream 5.0 Pro AI Generator を無料で試したい。ただし、生成画像をそのまま本番のOGPへ置くと、サイズ、トリミング、文字の再現性が毎回変わる。

この記事では、ブラウザで生成した画像を Node.js + sharp で1200×630pxのWebPへ正規化し、公開前に機械的なQAを通す。モデルをAPIから呼ぶ話ではないため、APIキーは不要だ。

注:本文には検証対象としてFlyne AIのモデルページへのリンクを含む。無料枠、必要クレジット、利用条件は変わる可能性があるため、実行前に画面で確認してほしい。

先に結論:「安定」は同じ絵を出すことではない

画像生成AIで、毎回まったく同じピクセルを得ることを「安定」と定義すると運用が苦しくなる。実務では、次の4点を固定した方がよい。

  1. 生成時の用途、構図、禁止事項
  2. 最終キャンバスの幅と高さ
  3. タイトルを置く安全領域
  4. 出力形式とファイル容量の上限

AIには背景素材を作らせ、最終サイズ、トリミング、文字、圧縮はコードで確定する。これなら生成結果に多少の差があっても、公開物の仕様は変わらない。

今回のゴールは次の通り。

項目 固定値
最終サイズ 1200 × 630 px
出力形式 WebP
WebP品質 82
容量予算 450 KB以下
テキスト SVGで後から合成
AI側の役割 文字なしの背景候補を作る

全体フロー

処理は「仕様を決める → 候補を生成する → Node.jsで検査・整形する → Web向け画像を出力する」の4段階に分ける。

生成モデルの評価と、配信用ファイルの検証を分離するのがポイントだ。モデルの見た目が良くても、出力サイズが違えばQAは失敗させる。
qiita-seedream5-ogp-qa-workflow-16x9.png

1. Node.js環境を用意する

sharpの現行ドキュメントはNode.js 20.9.0以上をサポート対象としている。まず空のディレクトリで初期化する。

mkdir seedream-ogp-qa
cd seedream-ogp-qa
npm init -y
npm install sharp
mkdir input dist scripts

この記事のスクリプトはES Modulesで動かすため、package.jsonへ次を追加する。

{
  "type": "module",
  "scripts": {
    "build:ogp": "node scripts/build-ogp.mjs"
  }
}

2. Seedream 5.0 Proで背景候補を作る

Flyne AIのSeedream 5.0 Pro AI Image Generatorには、記事確認時点で Free Trial、プロンプト入力、参照画像、比率、解像度の選択画面が表示されている。

今回はOGP用なので、モデル内にタイトルを書かせない。文字は後からSVGで重ねた方が、表記、位置、フォントサイズをコードで固定できる。

プロンプト例:

Create a clean editorial background for a developer tool launch.
Wide landscape composition, one abstract software dashboard object near the center,
subtle depth, white and pale gray environment, restrained green and blue accents.
Keep generous negative space on the left for a title overlay.
No readable text, no letters, no numbers, no logos, no watermark, no fake analytics.

同じプロンプトで3枚ほど候補を作り、次の条件で1枚を選ぶ。

  • 主役が端に寄りすぎていない
  • 左側にタイトルを置ける余白がある
  • 小さな画面でも主役を判別できる
  • 文字、ロゴ、意味のないUIコピーが混ざっていない

選んだ画像を input/seedream-background.png として保存する。元画像のサイズは1200×630pxでなくてもよい。後段で中央または注目領域を基準に切り抜く。

3. 安全領域を先に決める

1200×630pxの全面を重要情報で埋めると、一覧カードや別のSNSプレビューで端が欠けやすい。この記事のサンプルでは、タイトルを左から72px、上から72pxの位置に置き、右側は生成画像の主役に使う。

これはプラットフォーム共通の公式値ではなく、このプロジェクトで採用する設計ルールだ。別媒体へ出す場合は、実際のプレビューを見て調整する。

AI側の背景とコード側のタイトルを分離すると、次の修正が生成し直しなしで行える。

  • 日本語タイトルだけ差し替える
  • 2行目だけ短くする
  • 背景の明度を落として可読性を上げる
  • PCとモバイルの切り抜きを見ながら主役位置を選ぶ
  • qiita-seedream5-ogp-safe-area-16x9.png

4. sharpでOGP画像を正規化する

次を scripts/build-ogp.mjs として保存する。

import path from "node:path";
import { mkdir, stat } from "node:fs/promises";
import sharp from "sharp";

const inputPath = process.argv[2];
const outputPath = process.argv[3] ?? "dist/ogp.webp";

if (!inputPath) {
  console.error(
    "Usage: node scripts/build-ogp.mjs <input> [output]",
  );
  process.exit(1);
}

const WIDTH = 1200;
const HEIGHT = 630;
const MAX_BYTES = Number(process.env.MAX_BYTES ?? 450_000);
const line1 =
  process.env.OG_TITLE_LINE1 ?? "Seedream 5.0 Pro";
const line2 =
  process.env.OG_TITLE_LINE2 ?? "OGP画像を安定化";

const escapeXml = (value) =>
  value
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&apos;");

const source = await sharp(inputPath).metadata();
if (!source.width || !source.height) {
  throw new Error("入力画像の幅または高さを取得できません");
}

const overlay = Buffer.from(`
<svg width="${WIDTH}" height="${HEIGHT}"
  viewBox="0 0 ${WIDTH} ${HEIGHT}"
  xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="shade" x1="0" x2="1">
      <stop offset="0%" stop-color="#0b1020" stop-opacity="0.88"/>
      <stop offset="72%" stop-color="#0b1020" stop-opacity="0.36"/>
      <stop offset="100%" stop-color="#0b1020" stop-opacity="0"/>
    </linearGradient>
  </defs>
  <rect width="${WIDTH}" height="${HEIGHT}" fill="url(#shade)"/>
  <rect x="72" y="72" width="10" height="486" rx="5"
    fill="#55c500"/>
  <text x="112" y="260"
    fill="#ffffff"
    font-family="Arial, Helvetica, sans-serif"
    font-size="66"
    font-weight="700">
    ${escapeXml(line1)}
  </text>
  <text x="112" y="344"
    fill="#ffffff"
    font-family="Arial, Helvetica, sans-serif"
    font-size="54"
    font-weight="700">
    ${escapeXml(line2)}
  </text>
</svg>
`);

await mkdir(path.dirname(outputPath), { recursive: true });

await sharp(inputPath)
  .rotate()
  .resize({
    width: WIDTH,
    height: HEIGHT,
    fit: "cover",
    position: "attention",
  })
  .composite([{ input: overlay, top: 0, left: 0 }])
  .webp({ quality: 82, smartSubsample: true })
  .toFile(outputPath);

const output = await sharp(outputPath).metadata();
const file = await stat(outputPath);

const checks = {
  width: output.width === WIDTH,
  height: output.height === HEIGHT,
  format: output.format === "webp",
  fileSize: file.size <= MAX_BYTES,
};

console.log({
  input: {
    path: inputPath,
    width: source.width,
    height: source.height,
    format: source.format,
  },
  output: {
    path: outputPath,
    width: output.width,
    height: output.height,
    format: output.format,
    bytes: file.size,
  },
  checks,
});

if (Object.values(checks).includes(false)) {
  process.exitCode = 1;
}

sharpのmetadata()は画像ヘッダーから幅、高さ、形式などを取得する。resize()coverは縦横比を維持しながら指定サイズを覆うように切り抜き、attentionは明るさ、彩度、肌色などを使って注目領域を選ぶ。最後にWebPへ変換し、出力をもう一度検査する。

文字列をそのままSVGへ入れず、escapeXml()を通している点も重要だ。記事タイトルに&<が含まれてもSVGを壊しにくい。

5. 実行する

OG_TITLE_LINE1="Seedream 5.0 Pro" \
OG_TITLE_LINE2="OGP画像QA" \
npm run build:ogp -- \
  input/seedream-background.png \
  dist/seedream-ogp.webp

成功時でも結果のJSONを確認する。見るべき場所は次の4つだ。

  • checks.widthtrue
  • checks.heighttrue
  • checks.formattrue
  • checks.fileSizetrue

容量だけ失敗した場合は、すぐにキャンバスを小さくするのではなく、まずWebP品質を82から76程度へ下げる。細い線やUI要素が崩れる場合は、品質を戻し、背景の細かなノイズを減らした候補へ差し替える。

CIへ入れる場合

生成済みの背景画像をリポジトリへ置けるなら、CIでも同じコマンドを実行できる。

name: Validate OGP

on:
  pull_request:
    paths:
      - "input/**"
      - "scripts/build-ogp.mjs"

jobs:
  ogp:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run build:ogp -- input/seedream-background.png dist/ogp.webp

出力サイズや形式が違えばスクリプトが終了コード1を返すため、公開前に差分を止められる。ただし、主役が不自然に切れていないか、タイトルが読みやすいかという視覚確認までは自動化しない。

よくある失敗と切り分け

タイトルが背景へ埋もれる

AIへ「暗い背景」を追加するより、SVGのグラデーション不透明度を上げる方が再現性が高い。背景生成と文字可読性の問題を分けて直す。

主役が切れる

まずプロンプトで主役を中央寄りにする。それでも不安定なら、position: "attention"position: "centre"へ変更し、候補画像側で位置を調整する。

450KBを超える

450KBはこの記事のプロジェクト予算であり、Qiitaや全SNSの共通上限ではない。品質を下げる、背景のノイズを減らす、透明部分をなくす、の順で確認する。

AI画像内の文字が崩れる

背景プロンプトで文字を禁止し、タイトルはSVG合成へ寄せる。モデルの文字生成能力を評価したい場合でも、配信用OGPの工程とは別テストにした方がよい。

APIは必要?

この手順では必要ない。ブラウザから画像を生成し、ダウンロードしたファイルをローカルで処理する。Flyne AIの対象ページには記事確認時点でAPI説明が見当たらないため、APIが使える前提では書いていない。

自動生成APIが必要なチームは、利用するプロバイダーの公式API仕様、料金、保存方針を別途確認し、背景生成部分だけを置き換える。後段のsharp QAはそのまま再利用できる。

まとめ

Seedream 5.0 Pro AI Generator を実務へ入れるときは、「同じ画像が出るか」より「違う候補が来ても同じ公開仕様へ着地できるか」を設計した方がよい。

まずSeedream 5.0 Proを無料トライアル画面で確認し、文字なしの背景を1枚作る。その後はNode.jsで1200×630px、WebP、容量予算、タイトル位置を固定する。AIの自由度を背景へ限定し、配信要件をコードへ移すと、画像生成を本番フローへ組み込みやすくなる。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?