猫の手ツール

Algorithm & UI/UX

デジタルな画像を「紙」にする:
ノイズ生成と日本語レイアウトの実装術

「新聞らしさ」の正体は、かすかなザラつきと特有の文字組みにあります。本記事では、Canvas上でランダムノイズを生成し、マルチバイト文字を正確に配置するためのフロントエンドの実装アプローチを掘り下げます。

このツールの入力から出力まで

現行コードの確認日:

入力
写真と新聞の見出し・本文などを入力します。
処理
紙面色、写真の枠、縦横の文字配置をCanvasで合成します。
出力
入力は長辺 1500px 以下に縮小し、800×1130px の JPEG(品質指定 0.9)にします。

まず確認する点:入力文の事実確認や記事生成は行いません。縦書きの句読点や長い見出しの収まりをプレビューで見ます。

仕上がりの例

写真を白黒にし、新聞の号外風にした例です。

加工前・加工後
左は座っている茶トラの愛猫の写真。右は猫の白黒写真と号外の見出しを組み合わせた新聞風画像。

加工前・加工後

左は座っている茶トラの愛猫の写真。右は猫の白黒写真と号外の見出しを組み合わせた新聞風画像。

掲載画像はサイトにある既存の公開作例です。保存済みの資料では運営者の愛猫の写真を使用しています。今回の確認日が、この作例を実行した日を表すわけではありません。

保存済み検証記録の条件を見る

資料の種類は「ツールの出力画像を保存した記録」です。公開作例と保存済み記録で素材や色などが異なる場合があるため、下の数値は保存済み検証記録の条件として読んでください。

記録の入力画像
800×1222px (JPEG)
記録の出力画像
800×1130px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
記録で選択されていた項目白黒—
メイン見出し猫、今日も寝る初期値 世紀の大発見!
サブ見出し日なたの特等席を完全占拠初期値 世界中が注目する驚きのニュース
ズーム100初期値 100 / 範囲 50〜300

記録では「完成!号外を出す」から完成表示へ進んでいます。初期値と記録値を比べてから、効果を1項目ずつ変えると作用を確認しやすくなります。

資料ファイルの作成日は実行日として扱っていません。個別端末の処理速度や、ほかの写真に対する検出・加工の精度を測定した資料でもありません。

実装の確認箇所:src/pages/image/newspaper/index.astro。以下のコード抜粋と出力条件は、この本番実装に基づいて説明します。

仕組みを読み進めるときは、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)、メモリ管理と画像処理(画素バッファ、縮小と容量予算)が参考になります。

1. アナログな質感を再現する「プロシージャル・ノイズ」生成

デジタルのキャンバスに単色を塗るだけでは、清潔すぎて「新聞紙」には見えません。本ツールでは、背景を描画した直後に Math.random() を用いた数千回の微細なピクセル描画を重ねることで、紙の繊維感やインクのムラを再現しています。

暗いノイズと明るいノイズの2層構造にすることで、単なるグレーではなく、奥行きのある質感を生み出しています。画像アセットを使わないことで、紙模様の画像ファイルを追加取得せずに描けます。出力は固定寸法のビットマップです。

横幅で行を区切る処理を読みやすくした例です。本文の長さを制限する処理は別途必要です。

function wrapLines(ctx, text, maxWidth) {
  const lines = [];
  let line = '';
  for (const char of text) {
    if (line && ctx.measureText(line + char).width > maxWidth) {
      lines.push(line); line = char;
    } else line += char;
  }
  lines.push(line);
  return lines;
}

2. 日本語特有の「1文字判定」による動的改行アルゴリズム

Canvasの fillText にはCSSのような自動改行機能がありません。特に新聞のような多段組みレイアウトでは、指定された幅(カラム幅)で正確に改行する必要があります。

本ツールでは、マルチバイト文字を1文字ずつ measureText でスキャンし、累積幅がカラム幅を超えた瞬間に Y座標 を更新して改行するロジックを実装しています。これにより、指定幅に応じて行を増やせます。ただし高さの上限・禁則処理・絵文字のまとまりは扱わないため、長文は下にはみ出す場合があります。

3. ルミナンス計算による「新聞写真」のエミュレーション

「新聞風」に見せるためには、写真のモノクロ化も重要です。単に彩度を下げるのではなく、人間の視覚特性(ルミナンス)に基づいた加重平均を用いてRGB値を計算することで、新聞のモノクロ印刷に近いコントラストを実現しています。

この処理は getImageData を通じてピクセル単位で直接実行されるため、Canvas の filter に依存せず写真の色を変更します。端末のフォントや描画環境まで同一にするものではありません。

出力の仕様と確認する点

入力は長辺 1500px 以下に縮小し、800×1130px の JPEG(品質指定 0.9)にします。写真は紙面の指定領域で切り抜くので、ドラッグとズームで見せたい部分を合わせます。

紙の粒は黒い点 1500 個と白い点 800 個を再描画ごとにランダム配置します。同じ設定でも完全に同じ模様になるわけではなく、紙の繊維を物理的に再現する処理ではありません。

長い見出しや本文は、他の文字や画像への重なりを確認してください。新聞風の画像を作る機能であり、記事の内容を検証したり実在媒体の発行物を作成したりする機能ではありません。