Save drawing as PNG button
Adds a "๐พ Save PNG" button to the toolbar that downloads the current pixel drawing as a 512ร512 picture file named pixel-art.png. Empty squares are transparent and grid lines are not included.
What it does
- Add a toolbar button labeled "๐พ Save PNG" (id saveBtn, class "tool") placed after the Clear button.
- On click, render the current grid onto an offscreen canvas of size GRID_SIZE ร 16 by GRID_SIZE ร 16 pixels (512ร512 for the existing grid). Each grid cell becomes a solid 16ร16 pixel block, so edges are crisp.
- Cells with no color (empty or erased) are left transparent, not filled with white.
- Grid lines are never drawn into the exported image, regardless of whether they are shown on screen.
- Download the result as a PNG with the fixed file name "pixel-art.png" using a temporary link with the download attribute. Prefer canvas.toBlob with an object URL (revoke the URL after about 1 second). Fall back to a canvas.toDataURL data URL if toBlob is unavailable or returns nothing.
- No network requests; everything happens locally in the browser.
- Update the README: list the Save PNG button (describe 512ร512 size, transparent empty squares, no grid lines, file name pixel-art.png), and change the closing note to say the page doesn't keep the drawing itself, so use Save PNG to keep it, since refreshing or closing starts with a blank grid.
Safety check โ Safe
The change only draws the on-screen grid to a canvas and triggers a local file download; it makes no network requests, adds no dependencies, and touches nothing outside the drawing and README text.
Conversation that created this patch
@devon
Add a button to save the drawing as a PNG image.
AI
I added a **๐พ Save PNG** button to the toolbar, after Clear. Click it and your browser downloads the drawing as a picture file called "pixel-art.png". I checked that the code has no errors, but I couldn't open it in a real browser here, so it's worth one quick test save.
- **Size:** the picture is 512ร512 pixels. Each square on the grid becomes a sharp 16ร16 block, so it isn't a tiny thumbnail and the edges don't go blurry.
- **Empty squares are see-through, not white.** Most pixel art is saved this way, so you can put it on any background. If you open the file in a basic image viewer, those parts may look white, grey or checkered.
- **No grid lines:** the faint lines are never included, even when they're switched on.
- **File name:** every save uses the same name. If you save more than once, your browser may number the copies or ask what to do.
I also updated the instructions in the README to explain the new button.
Code changes (for the curious, 2 files) ยท raw
README.md +2 โ1
@@ -14,7 +14,8 @@ A small pixel art drawing app that runs in your web browser. Everything lives in | |
- **Eraser**: click the Eraser button, then click or drag to erase. Clicking with the right mouse button also erases. Click **Brush** to go back to painting. | |
- **Grid lines**: turns the faint lines between squares on or off. | |
- **Clear**: wipes the whole drawing. It asks you first, just in case. | |
| + | - **Save PNG**: downloads your drawing as a picture file called `pixel-art.png` (512ร512, each square becomes a crisp 16ร16 block). Empty squares are see-through in the saved picture. Grid lines are not included. |
| |
It also works with touch screens and drawing pens. | |
| |
| โ | Note: the drawing isn't saved. Refreshing or closing the page starts you with a blank grid. |
| + | Note: the drawing isn't kept by the page itself. Use **Save PNG** if you want to keep it, because refreshing or closing the page starts you with a blank grid. |
index.html +39 โ0
@@ -130,6 +130,7 @@ | |
<button class="tool" id="eraserBtn" type="button">๐งฝ Eraser</button> | |
<button class="tool" id="linesBtn" type="button">โฆ Grid lines</button> | |
<button class="tool" id="clearBtn" type="button">๐๏ธ Clear</button> | |
| + | <button class="tool" id="saveBtn" type="button">๐พ Save PNG</button> |
</div> | |
| |
<div id="grid" class="show-lines"></div> | |
@@ -158,6 +159,7 @@ | |
const eraserBtn = document.getElementById("eraserBtn"); | |
const linesBtn = document.getElementById("linesBtn"); | |
const clearBtn = document.getElementById("clearBtn"); | |
| + | const saveBtn = document.getElementById("saveBtn"); |
| |
let color = COLORS[0]; | |
let erasing = false; | |
@@ -256,6 +258,43 @@ | |
} | |
}); | |
| |
| + | // Save the drawing as a PNG image. Each square becomes a block of |
| + | // EXPORT_SCALE x EXPORT_SCALE pixels so the picture isn't tiny. |
| + | // Empty (erased) squares are saved as transparent. |
| + | const EXPORT_SCALE = 16; |
| + | saveBtn.addEventListener("click", function () { |
| + | const canvas = document.createElement("canvas"); |
| + | canvas.width = SIZE * EXPORT_SCALE; |
| + | canvas.height = SIZE * EXPORT_SCALE; |
| + | const ctx = canvas.getContext("2d"); |
| + | cells.forEach(function (cell, i) { |
| + | const c = cell.style.backgroundColor; |
| + | if (!c) return; |
| + | ctx.fillStyle = c; |
| + | ctx.fillRect((i % SIZE) * EXPORT_SCALE, Math.floor(i / SIZE) * EXPORT_SCALE, |
| + | EXPORT_SCALE, EXPORT_SCALE); |
| + | }); |
| + | |
| + | const fileName = "pixel-art.png"; |
| + | function download(href, revoke) { |
| + | const a = document.createElement("a"); |
| + | a.href = href; |
| + | a.download = fileName; |
| + | document.body.appendChild(a); |
| + | a.click(); |
| + | a.remove(); |
| + | if (revoke) setTimeout(function () { URL.revokeObjectURL(href); }, 1000); |
| + | } |
| + | if (canvas.toBlob) { |
| + | canvas.toBlob(function (blob) { |
| + | if (blob) download(URL.createObjectURL(blob), true); |
| + | else download(canvas.toDataURL("image/png"), false); |
| + | }, "image/png"); |
| + | } else { |
| + | download(canvas.toDataURL("image/png"), false); |
| + | } |
| + | }); |
| + | |
linesBtn.classList.add("active"); | |
updateUI(); | |
})(); |