Skip to content

Instantly share code, notes, and snippets.

@greggman
Last active April 7, 2026 01:42
Show Gist options
  • Select an option

  • Save greggman/672cbda13e4a12bba07b0cc31236c15e to your computer and use it in GitHub Desktop.

Select an option

Save greggman/672cbda13e4a12bba07b0cc31236c15e to your computer and use it in GitHub Desktop.
Canvas Generate Images into Zip
img { width: 160px; }
/*bug-in-github-api-content-can-not-be-empty*/
import { Zip } from 'https://greggman.github.io/zipup/dist/zipup.module.js';
const hsl = (h, s, l) => `hsl(${h * 360 | 0}, ${s * 100}%, ${l * 100 | 0}%)`;
const hsla = (h, s, l, a) => `hsl(${h * 360 | 0}, ${s * 100}%, ${l * 100 | 0}%, ${a})`;
const rgb = (r, g, b) => `rgb(${r * 255 | 0}, ${g * 255 | 0}, ${b * 255 | 0})`;
const rgba = (r, g, b, a) => `rgba(${r * 255 | 0}, ${g * 255 | 0}, ${b * 255 | 0, a})`;
const lerp = (a, b, t) => a + (b - a) * t;
const w = 640;
const h = 480;
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
const zip = new Zip();
const numGroups = 4;
const numImages = 4;
for (let g = 0; g < numGroups; ++g) {
const ug = g / numGroups;
for (let i = 0; i < numImages; ++i) {
const ui = i / numImages;
ctx.clearRect(0, 0, w, h);
const hue = ug + lerp(0.0, 0.1, ui);
const sat = lerp(0.8, 1.0, ui);
const lum = lerp(0.4, 0.6, ui);
ctx.fillStyle = hsl(hue, sat, lum);
ctx.fillRect(0, 0, w, h);
ctx.lineWidth = 20;
ctx.strokeStyle = hsl(hue + 0.5, sat, lum);
ctx.strokeRect(0, 0, w, h);
ctx.font = `${h * 0.8}px monospace`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const f = String.fromCharCode(0x44 + g);
const im = String.fromCharCode(0x30 + i);
const s = `${f}${im}`;
ctx.strokeStyle = 'black';
ctx.strokeText(s, w / 2, h / 2);
ctx.fillStyle = hsl(hue + 0.5, sat, lum);
ctx.fillText(s, w / 2, h / 2);
const blob = await new Promise(resolve => canvas.toBlob(resolve));
const path = g > 0
? `folder-${f}/image-${im}.png`
: `image-${im}.png`;
zip.addFile(path, blob);
const img = new Image();
img.src = URL.createObjectURL(blob);
document.body.append(img);
}
}
const saveBlob = (function() {
const a = document.createElement('a');
document.body.appendChild(a);
a.style.display = 'none';
return function saveData(blob, fileName) {
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
};
}());
saveBlob(await zip.finalize(), 'nested-images.zip');
{"name":"Canvas Generate Images into Zip","settings":{},"filenames":["index.html","index.css","index.js"]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment