画像をページ内に配置するとき、縦横比だけを見て「収まった」と判定すると、横か縦の片方がはみ出すケースを見落とします。正常系より先に、受け付けない入力と、結果が守るべき条件を決めます。
この記事の関数は矩形の数値を計算するだけです。画像のデコード、向きのメタデータの解釈、PDF の生成は行いません。座標の原点や描画 API の扱いは、実際の組み込み先で別途確認してください。
先に失敗させる
ページの幅と高さから左右・上下それぞれの余白を引いたとき、使える領域が空になってはいけません。例えば幅 600、高さ 800 のページで余白を 300 にすると、横方向の残りは 0 です。この入力は例外にします。負の余白や無限大も受け付けません。
画像・ページの各寸法には、有限の数値で 1 以上 1,000,000 以下という範囲を設けます。文字列の "1200" は数値に見えても拒否します。この範囲はサンプルのために選んだ予算であり、一般的な規格でも、本番コードの入力検証と同一だという主張でもありません。
別の数値ハーネスでは、560 × 760 へ引き伸ばす計算が元の 2:1 の比率を壊すことと、倍率の上限を外すと 100 × 50 の小画像を拡大してしまうことも比較しました。縦横比と非拡大の方針が必要な理由を示す負例です。以下の短いコードには、この2つの比較は含めていません。
正常値で守る四つの条件
幅と高さには同じ倍率を掛けます。倍率は、使用可能な幅に対する比、使用可能な高さに対する比、そして 1 のうち最小値です。したがって、どちらの辺も余白の内側に収まり、元の縦横比を維持します。浮動小数点の比較では誤差を考慮してください。
残った空間は左右と上下でそれぞれ等分します。また倍率を 1 以下に制限するため、小さい画像はこの計算では拡大されません。ここでは元画像の幅・高さをページ座標と同じ数値対応で扱い、元の1単位を高々ページの1単位に対応させます。物理的な DPI 換算ではありません。
export function containRect(iw, ih, pw, ph, margin) {
if (![iw, ih, pw, ph].every(v =>
typeof v === "number" && Number.isFinite(v) && v >= 1 && v <= 1e6
)) throw new RangeError("dimensions must be numbers from 1 to 1000000");
if (typeof margin !== "number" || !Number.isFinite(margin) ||
margin < 0 || 2 * margin >= Math.min(pw, ph)) {
throw new RangeError("margin leaves no usable rectangle");
}
const scale = Math.min(1, (pw - 2 * margin) / iw, (ph - 2 * margin) / ih);
const width = iw * scale;
const height = ih * scale;
return { x: (pw - width) / 2, y: (ph - height) / 2, width, height };
}
次の検査を同じファイルの関数の後に置き、example.mjs として node example.mjs で実行できます。成功時は何も表示されません。入力の拒否も同時に確かめます。
import assert from "node:assert/strict";
assert.deepEqual(containRect(1200, 600, 600, 800, 20),
{ x: 20, y: 260, width: 560, height: 280 });
assert.deepEqual(containRect(100, 50, 600, 800, 20),
{ x: 250, y: 375, width: 100, height: 50 });
for (const args of [
["1200", 600, 600, 800, 20],
[1200, 600, 600, 800, 300],
[0, 600, 600, 800, 20],
]) assert.throws(() => containRect(...args), RangeError);
最初の例では使用可能領域が 560 × 760 です。横幅が制約となり、結果は 560 × 280、位置は (20, 260) になります。次の 100 × 50 は拡大せず、(250, 375) に配置されます。余白の内側にあることは横と縦の両方で確認します。
2026-10-28 に Codex エージェントが Darwin 上の Node v22.23.4 で数値のみを検査しました。正常9件、異常12件、本番ヘルパーとの有効な描画寸法の比較9件、負のコントロール2件です。この比較は実装全体や入力方針の一致を証明しません。エンコード済み画像や PDF の試験も含みません。
開示:この記事は Yan Wang / LensUp 向けに GPT-6.1 Terra が下書きしました。Codex エージェントが 2026-10-28 に正式ソースと公開ページの文言を確認し、上記の数値検査を実行しました。新たな HEIC・画像から PDF への変換、ブラウザー・電話・プリンターでの出力、または人間のオーナーによるテストは行っていません。