// Builds the three demo files in the browser from CC0 scikit-image photos // (coffee.png by Rachel Michetti, chelsea.png by Stefan van der Walt), so the // Space needs no binary assets. Mirrors scripts/make_samples.py. const SK = "https://cdn.jsdelivr.net/gh/scikit-image/scikit-image@v0.24.0/skimage/data/"; const fetchBitmap = async (name) => createImageBitmap(await (await fetch(SK + name)).blob()); const toBlob = (c, type, q) => new Promise((r) => c.toBlob(r, type, q)); function canvasOf(w, h) { const c = document.createElement("canvas"); c.width = w; c.height = h; return [c, c.getContext("2d")]; } async function jpegBitmap(source, w, h, quality) { const [c, ctx] = canvasOf(w, h); ctx.drawImage(source, 0, 0); return createImageBitmap(await toBlob(c, "image/jpeg", quality)); } // ---- PNG tEXt chunk insertion (to mimic Stable Diffusion's "parameters" metadata) const CRC = (() => { const t = new Uint32Array(256); for (let n = 0; n < 256; n++) { let c = n; for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; t[n] = c >>> 0; } return t; })(); function crc32(bytes) { let c = 0xffffffff; for (const b of bytes) c = CRC[(c ^ b) & 0xff] ^ (c >>> 8); return (c ^ 0xffffffff) >>> 0; } function withTextChunk(png, keyword, text) { const data = new TextEncoder().encode(`${keyword}\0${text}`); const chunk = new Uint8Array(12 + data.length), dv = new DataView(chunk.buffer); dv.setUint32(0, data.length); chunk.set([0x74, 0x45, 0x58, 0x74], 4); // "tEXt" chunk.set(data, 8); dv.setUint32(8 + data.length, crc32(chunk.subarray(4, 8 + data.length))); const at = 33; // after the 8-byte signature + 25-byte IHDR chunk const out = new Uint8Array(png.length + chunk.length); out.set(png.subarray(0, at), 0); out.set(chunk, at); out.set(png.subarray(at), at + chunk.length); return out; } export async function makeSample(kind) { if (kind === "photo") { const coffee = await fetchBitmap("coffee.png"); const [c, ctx] = canvasOf(coffee.width, coffee.height); ctx.drawImage(coffee, 0, 0); return new File([await toBlob(c, "image/jpeg", 0.92)], "photo.jpg", { type: "image/jpeg" }); } if (kind === "edited") { const [coffee, cat] = await Promise.all([fetchBitmap("coffee.png"), fetchBitmap("chelsea.png")]); const base = await jpegBitmap(coffee, coffee.width, coffee.height, 0.85); const patch = await jpegBitmap(cat, cat.width, cat.height, 0.3); // different compression history const [c, ctx] = canvasOf(coffee.width, coffee.height); ctx.drawImage(base, 0, 0); ctx.drawImage(patch, 100, 50, 200, 200, 300, 100, 200, 200); return new File([await toBlob(c, "image/jpeg", 0.85)], "edited.jpg", { type: "image/jpeg" }); } // "ai-tagged": a procedurally generated image carrying Stable-Diffusion-style metadata const N = 512, [c, ctx] = canvasOf(N, N), img = ctx.createImageData(N, N); for (let y = 0; y < N; y++) for (let x = 0; x < N; x++) { const xx = x / N, yy = y / N, i = (y * N + x) * 4; img.data[i] = (0.5 + 0.5 * Math.sin(6 * xx + 3 * Math.sin(4 * yy))) * 255; img.data[i + 1] = (0.5 + 0.5 * Math.sin(5 * yy + 2 * Math.cos(3 * xx))) * 255; img.data[i + 2] = (0.5 + 0.5 * Math.cos(4 * (xx + yy))) * 255; img.data[i + 3] = 255; } ctx.putImageData(img, 0, 0); const png = new Uint8Array(await (await toBlob(c, "image/png")).arrayBuffer()); const tagged = withTextChunk(png, "parameters", "abstract flowing colors\nSteps: 30, Sampler: DPM++ 2M, CFG scale: 7, Model: sd_xl_base_1.0 (demo file)"); return new File([tagged], "ai-tagged.png", { type: "image/png" }); }