営業スライド資料をHTML→16:9 PDFで量産+写真整備パイプライン
HTMLでスライド設計→Playwrightで16:9 PDF化→実写真とAI画像を混在。ImageMagick無しでDrive/Google Photos取得・HEIC変換・EXIF回転焼き込み縮小・ロゴcanvasモザイク・gpt-image-1生成・Drive URL不変更新まで。固定px設計時の@page一致(フッター重なり)の罠も収録。
約6,800トークンの節約 (API料金換算で約10円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「営業スライド資料をHTML→16:9 PDFで量産+写真整備パイプライン」は、業務自動化カテゴリのAI指示書(MDファイル)です。HTMLでスライド設計→Playwrightで16:9 PDF化→実写真とAI画像を混在。ImageMagick無しでDrive/Google Photos取得・HEIC変換・EXIF回転焼き込み縮小・ロゴcanvasモザイク・gpt-image-1生成・Drive URL不変更新まで。固定px設計時の@page一致(フッター重なり)の罠も収録。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約6,800トークン(API料金換算で約10円)・76%のトークンを節約できます。
- カテゴリ
- 業務自動化
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約9,000トークン
- この巻物使用時
- 約2,200トークン
- 節約量
- 約6,800トークン (約10円)
- 更新日
- 2026-08-19
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/html-16-9-pdf/raw を読み込んで、この指示書どおりに実装して"
中身
営業スライド資料(媒体資料・提案書)を HTML→16:9 PDF で量産し、写真を整えるパイプライン
ImageMagick / sharp を入れずに、HTML でスライドを組み → Playwright で 16:9 PDF 化 → 実写真と AI 画像を混在させて整えるまでを全自動で回す型。デザイン反復・写真差し替えが多い媒体資料/ピッチデックに効く。Node と playwright-core(Chrome チャネル)だけで完結する。
前提: Node 18+、playwright-core(既存プロジェクトの node_modules/playwright-core を流用可)、システムに Google Chrome。画像生成を使うなら OpenAI API キー。Drive アップを使うなら Google OAuth のリフレッシュトークン(clasp の ~/.clasprc.json 等)。
0. スライドを 1600×900px 固定で設計する(最重要の罠)
スライドは固定ピクセル座標(position:absolute; left:96px; bottom:34px など)で組むと速いが、印刷時に必ず事故る。
- 画面用
.slide{width:1600px;height:900px}で作ったら、@media printの@page{size:1600px 900px}と.slide{width:1600px;height:900px}を設計値に一致させる。 - ここで
@page{size:13.333in 7.5in}(=1280×720px @96dpi)にすると、固定 px 座標だけスケールされずキャンバスだけ縮む→フッター/ロゴが本文に重なる。16:9 を保ちたいだけなら px で指定すればよい(PDF ページが物理的に大きくなるだけで比率は同じ)。 - 症状「複数ページでフッターやロゴが本文に被る」はほぼこれ。design px と
@pagepx を一致させれば全ページ一括で直る。
@media print {
@page { size: 1600px 900px; margin: 0; }
html, body { margin: 0; padding: 0; background: #fff; }
.slide { width: 1600px; height: 900px; page-break-after: always; break-after: page; }
.slide:last-child { break-after: auto; }
}
1. HTML → PDF(Playwright / システム Chrome)
// html-to-pdf.mjs 使い方: node html-to-pdf.mjs deck.html out.pdf
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const { chromium } = require('<playwright-core への絶対パス>'); // 既存プロジェクトの node_modules を流用可
const [inFile, outFile] = process.argv.slice(2);
const b = await chromium.launch({ channel: 'chrome', headless: true });
const p = await b.newPage();
await p.goto('file:///' + inFile.replace(/\\/g, '/'), { waitUntil: 'networkidle' });
await p.pdf({ path: outFile, printBackground: true, preferCSSPageSize: true });
await b.close();
channel:'chrome'でシステム Chrome を使う(フォント・絵文字が安定)。preferCSSPageSize:trueで上の@pageを尊重。<img src="img/foo.jpg">はfile://相対で解決される。Chrome は<img>に EXIF 回転を自動適用する(スマホ縦写真がそのまま正しい向きで出る)。
2. ImageMagick 無しで画像を取得する(公開共有前提)
- Google Drive 公開ファイル:
https://drive.google.com/uc?export=download&id=<FILE_ID>(〜25MB は確認画面なしで直接バイナリ)。 - HEIC を JPEG 化: ローカルに HEIC デコーダが無くても
https://drive.google.com/thumbnail?id=<FILE_ID>&sz=w2000がJPEG サムネイル(長辺 2000px まで)を返す。iPhone 写真の取り込みに有効。 - Google Photos 共有リンク: ページ HTML を取得し
lh3.googleusercontent.com/pw/<token>を正規表現で抜き、=w2000を付けて DL(=w<幅>で解像度指定)。 - 権限の壁:
drive.fileスコープの OAuth(clasp 等)は自分のアプリが作っていないファイルの本文 DL は 403(メタデータは可)。Google Slides API が GCP プロジェクトで無効なら 403(自分が有効化できないプロジェクトだと詰む)。非公開 Slides の 1 ページだけ画像で欲しい時は「リンクを知っている全員(閲覧)」共有にしてからhttps://docs.google.com/presentation/d/<ID>/export/png?pageid=<PAGE_OBJECT_ID>で取る(pageidは編集 URL のslide=id.xxxxのxxxx)。
3. EXIF 回転の焼き込み+縮小(Chrome 要素スクショ方式)
Read/埋め込み先によっては EXIF 回転を無視して横倒しになる。Chrome はスクショ時に回転を適用するので、それを使って回転を焼き込みつつ長辺 1400px に縮小する。フル解像度のまま PDF に埋めると数十 MB に膨れるので必須。
// data URI で読ませるのがコツ(file:// は setContent の about:blank origin から CORS で読めない)
const url = 'data:image/jpeg;base64,' + fs.readFileSync(f).toString('base64');
await page.setContent(`<style>*{margin:0}img{display:block;max-width:1400px;max-height:1400px}</style><img id=i src="${url}">`, { waitUntil: 'load' });
await page.waitForFunction(() => { const i = document.getElementById('i'); return i && i.complete && i.naturalWidth > 0; });
const el = await page.$('#i');
await el.screenshot({ path: out, type: 'jpeg', quality: 82 });
これで縦写真も正しい向き・軽量な JPEG になる。PDF が 77MB→3MB 級に落ちる。
4. ロゴ / 個人情報のモザイク(canvas ピクセル化)
写真に他社ロゴや個人が写る場合、canvas で矩形をピクセル化する。座標はグリッドを焼いた画像を目視して確定するのが速い。
// mosaic.mjs node mosaic.mjs in.jpg out.jpg "x,y,w,h;x,y,w,h;..."
const dataUrl = await page.evaluate(async ({ b64, rects }) => {
const img = new Image();
await new Promise(r => { img.onload = r; img.src = 'data:image/jpeg;base64,' + b64; });
const c = document.getElementById('c'); c.width = img.naturalWidth; c.height = img.naturalHeight;
const ctx = c.getContext('2d'); ctx.drawImage(img, 0, 0);
const block = 22; // 大きいほど粗い=判読不可
for (const [x, y, w, h] of rects) {
const sw = Math.max(1, Math.round(w / block)), sh = Math.max(1, Math.round(h / block));
const t = document.createElement('canvas'); t.width = sw; t.height = sh;
t.getContext('2d').drawImage(c, x, y, w, h, 0, 0, sw, sh); // 縮小
ctx.imageSmoothingEnabled = false;
ctx.drawImage(t, 0, 0, sw, sh, x, y, w, h); // 戻す=モザイク
}
return c.toDataURL('image/jpeg', 0.85);
}, { b64, rects });
- 座標出し: 100px ごとに赤線+数値ラベルを焼いた
grid.jpgを作り、それを見てx,y,w,hを読む。横位置は正確に取れるが縦位置は目測がズレやすいので、1 回モザイクして結果を見て y を微調整する前提で。 blockは「元幅÷block」で縮小するので、大きいほどブロックが粗く判読不能。文字ロゴなら 18〜24。
5. AI 画像生成(OpenAI gpt-image-1)
実写真が「まばら・雑然・被写体が不適切」な時の穴埋めに。キーは .env.local に置いて gitignore。
const res = await fetch('https://api.openai.com/v1/images/generations', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${KEY}` },
body: JSON.stringify({ model: 'gpt-image-1', prompt, size: '1536x1024', quality: 'high', n: 1 }),
});
const b64 = (await res.json()).data[0].b64_json; // → PNG 保存 → §3 で JPEG 縮小
"嘘っぽい" を避けるプロンプト鉄則: photorealistic editorial photograph, full-frame DSLR, varied individuals of different age/gender/build, natural candid poses, realistic depth of field, no duplicated faces, no readable text on signage。「クローン顔・不自然な群衆・読める看板文字」が生成 AI 写真の 3 大ボロなので明示的に禁止する。
6. Drive へ URL 不変で更新(大きいバイナリを LLM コンテキストに載せない)
成果物 PDF は「同じ Drive ファイル ID を PATCH uploadType=media で上書き」すると共有 URL が変わらない(相手のブックマークが生きる)。OAuth のリフレッシュトークンでアクセストークンを取り、Drive API に multipart(新規)/ media(更新)で投げる。MCP の base64 ダウンロードで巨大ファイルをコンテキストに載せない“横流し”アップ経路として汎用に使える。
// トークン更新 → 更新は PATCH .../files/<ID>?uploadType=media、新規は POST .../files?uploadType=multipart
const tok = await fetch('https://oauth2.googleapis.com/token', { method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body: new URLSearchParams({ client_id, client_secret, refresh_token, grant_type:'refresh_token' }) }).then(r=>r.json());
await fetch(`https://www.googleapis.com/upload/drive/v3/files/<ID>?uploadType=media`, {
method: 'PATCH', headers: { Authorization:`Bearer ${tok.access_token}`, 'Content-Type':'application/pdf' },
body: fs.readFileSync('out.pdf') });
7. 全体の回し方(デザイン反復に強い)
- HTML でスライド設計(§0 の @page 一致を最初から入れる)
- 写真を集める(§2 取得 → §3 回転焼き込み&縮小、必要なら §4 モザイク / §5 AI 生成)
html-to-pdf.mjs(§1)→ PDF を 1 ページずつ実視認して検証(フッター重なり・向き・ロゴ露出)- OK なら §6 で Drive を URL 不変更新
- 修正指示が来たら該当
<img src>を差し替えて 3 に戻るだけ(数十秒で再ビルド)
検証を省かない: 生成/縮小/モザイクは「実際に PDF に出た絵」を目で見るまで成功と断言しない。特にモザイクは 1 回で座標が合わないのが普通。
よくある質問
+「営業スライド資料をHTML→16:9 PDFで量産+写真整備パイプライン」とは何ですか?
HTMLでスライド設計→Playwrightで16:9 PDF化→実写真とAI画像を混在。ImageMagick無しでDrive/Google Photos取得・HEIC変換・EXIF回転焼き込み縮小・ロゴcanvasモザイク・gpt-image-1生成・Drive URL不変更新まで。固定px設計時の@page一致(フッター重なり)の罠も収録。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約9,000トークンかかりますが、この巻物を使えば約2,200トークンで済みます。差し引き約6,800トークン(API料金換算で約10円)・76%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
Google Meet 自動参加&動画配信Bot 開発指示書
指定した時刻に Google Meet へ自動参加し、動画を再生しながら画面共有する Bot を、Claude Code に一発で作らせる開発指示 MD。朝会の定例動画配信・ウェビナーの自動放送に。
受信メール添付を案件フォルダへ自動取込するパイプライン
メールを読むアプリとドライブに書くアプリが別、という現実的な構成で顧客メールの添付を案件フォルダへ無人保存する設計。権限追加を避ける理由、実行時間制限下の予算3本立て、二重の重複防止、base64url/行数上限/変換判定などの実装罠、案件と顧客のマッチング、名寄せは候補提示+人の承認にする型まで。
Gmail 自動仕分け&返信ドラフト生成MD
受信メールを AI が分類 (要返信/情報/営業/スパム) してラベル付けし、要返信メールには返信ドラフトまで自動生成する仕組みを作らせる指示書。DWD (ドメイン全体委任) 設定手順込み。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア