/** * Procedurally-generated sample images. These need no network and are the * guaranteed-available samples (the remote photos in samples.ts may be * blocked offline or by cross-origin policy). */ import type { RawImage } from "./imageConvert.ts"; function makeCanvas(w: number, h: number): { canvas: HTMLCanvasElement; ctx: CanvasRenderingContext2D; } { const canvas = document.createElement("canvas"); canvas.width = w; canvas.height = h; const ctx = canvas.getContext("2d", { willReadFrequently: true }); if (!ctx) throw new Error("Could not get a 2D canvas context."); return { canvas, ctx }; } function readBack( canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D ): RawImage { const data = ctx.getImageData(0, 0, canvas.width, canvas.height); return { width: canvas.width, height: canvas.height, rgba: data.data }; } /** Smooth RGB field: red rises left→right, green top→bottom, blue diagonal. */ export function gradientImage(w = 320, h = 320): RawImage { const { canvas, ctx } = makeCanvas(w, h); const img = ctx.createImageData(w, h); for (let y = 0; y < h; y++) { for (let x = 0; x < w; x++) { const i = (y * w + x) * 4; img.data[i] = Math.round((255 * x) / (w - 1)); img.data[i + 1] = Math.round((255 * y) / (h - 1)); img.data[i + 2] = Math.round((255 * (x + y)) / (w + h - 2)); img.data[i + 3] = 255; } } ctx.putImageData(img, 0, 0); return readBack(canvas, ctx); } /** High-contrast colored shapes on white — good for edge-detection demos. */ export function shapesImage(w = 360, h = 280): RawImage { const { canvas, ctx } = makeCanvas(w, h); ctx.fillStyle = "#ffffff"; ctx.fillRect(0, 0, w, h); ctx.fillStyle = "#e23b3b"; ctx.beginPath(); ctx.arc(w * 0.32, h * 0.42, Math.min(w, h) * 0.22, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = "#2f7de1"; ctx.fillRect(w * 0.5, h * 0.18, w * 0.34, h * 0.34); ctx.fillStyle = "#2fae57"; ctx.beginPath(); ctx.moveTo(w * 0.62, h * 0.92); ctx.lineTo(w * 0.42, h * 0.58); ctx.lineTo(w * 0.86, h * 0.58); ctx.closePath(); ctx.fill(); ctx.strokeStyle = "#222222"; ctx.lineWidth = Math.max(2, w * 0.012); ctx.beginPath(); ctx.moveTo(0, h * 0.5); ctx.bezierCurveTo(w * 0.25, h * 0.1, w * 0.75, h * 0.95, w, h * 0.45); ctx.stroke(); return readBack(canvas, ctx); } /** Colored checkerboard — exercises many per-region filters. */ export function checkerImage(w = 320, h = 320, tiles = 8): RawImage { const { canvas, ctx } = makeCanvas(w, h); const palette = ["#222831", "#e2b53b", "#c0392b", "#16a085"]; const tw = w / tiles; const th = h / tiles; for (let ty = 0; ty < tiles; ty++) { for (let tx = 0; tx < tiles; tx++) { ctx.fillStyle = palette[(tx + ty) % palette.length]; ctx.fillRect(tx * tw, ty * th, Math.ceil(tw), Math.ceil(th)); } } return readBack(canvas, ctx); }