Skip to content

Instantly share code, notes, and snippets.

@benjamingorman
Created May 6, 2024 00:13
Show Gist options
  • Save benjamingorman/2fb3a3b6a6211f3e00ab10a16a5a836a to your computer and use it in GitHub Desktop.
Save benjamingorman/2fb3a3b6a6211f3e00ab10a16a5a836a to your computer and use it in GitHub Desktop.
Downscale oversized pixel art
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pixel Art Resizer</title>
<style>
#input-image {
max-width: 100%;
max-height: 500px;
}
#output-canvas {
border: 1px solid black;
image-rendering: pixelated;
}
.drop-area {
border: 1px solid black;
}
canvas {
margin: 4px;
}
</style>
</head>
<body>
<input type="file" id="file-input" accept=".png">
<br>
<div class="drop-area" id="dropArea">
<p>Drag & drop a PNG file here, or click to select file.</p>
<br>
<label for="scale">Scale:</label>
<input type="number" id="scale" min="1" value="8">
<br>
<label for="scale-factor">Zoom Factor:</label>
<input type="range" id="zoom-factor" min="1" max="16" value="1">
<br>
<button onclick="resizePixelArt()">Resize Pixel Art</button>
<button onclick="copyZoomedImage()">Copy Zoomed Image</button>
<br />
<canvas id="input-canvas"></canvas>
</div>
<br>
<canvas id="output-canvas" style="width: 100%; height: 100%;"></canvas>
<script>
// Function to handle file drop
function handleDrop(event) {
event.preventDefault();
var file = event.dataTransfer.files[0];
handleFile(file);
}
// Function to handle file selection
function handleFile(file) {
var reader = new FileReader();
reader.onload = function (e) {
var img = new Image();
img.onload = function () {
var canvas = document.getElementById('input-canvas');
var ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
};
img.src = e.target.result;
setTimeout(resizePixelArt, 100);
};
reader.readAsDataURL(file);
}
// Event listeners for drag and drop
var dropArea = document.getElementById('dropArea');
dropArea.addEventListener('dragenter', function (event) {
event.preventDefault();
dropArea.classList.add('drag-over');
});
dropArea.addEventListener('dragleave', function (event) {
event.preventDefault();
dropArea.classList.remove('drag-over');
});
dropArea.addEventListener('dragover', function (event) {
event.preventDefault();
});
dropArea.addEventListener('drop', function (event) {
event.preventDefault();
dropArea.classList.remove('drag-over');
handleDrop(event);
});
document.getElementById('file-input').addEventListener('change', function (event) {
var file = event.target.files[0];
var reader = new FileReader();
reader.onload = function (e) {
var img = new Image();
img.onload = function () {
var canvas = document.getElementById('input-canvas');
var ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
});
document.getElementById('zoom-factor').addEventListener('input', function () {
var zoomFactor = parseInt(this.value);
var outputCanvas = document.getElementById('output-canvas');
outputCanvas.style.width = (outputCanvas.width * zoomFactor) + 'px';
outputCanvas.style.height = (outputCanvas.height * zoomFactor) + 'px';
});
function resizePixelArt() {
var scale = parseInt(document.getElementById('scale').value);
var zoomFactor = parseInt(document.getElementById('zoom-factor').value);
var inputCanvas = document.getElementById('input-canvas');
var inputCtx = inputCanvas.getContext('2d');
var inputImageData = inputCtx.getImageData(0, 0, inputCanvas.width, inputCanvas.height);
var outputCanvas = document.getElementById('output-canvas');
var outputCtx = outputCanvas.getContext('2d');
outputCanvas.width = inputCanvas.width / scale;
outputCanvas.height = inputCanvas.height / scale;
outputCtx.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
for (var y = 0; y < inputCanvas.height; y += scale) {
for (var x = 0; x < inputCanvas.width; x += scale) {
var pixel = getMedianColor(inputCtx, x, y, scale, inputImageData);
outputCtx.fillStyle = 'rgb(' + pixel.join(',') + ')';
outputCtx.fillRect(x / scale, y / scale, 1, 1);
}
}
outputCanvas.style.width = inputCanvas.width * zoomFactor + 'px';
outputCanvas.style.height = inputCanvas.height * zoomFactor + 'px';
}
// Function to copy the zoomed image
function copyZoomedImage() {
var outputCanvas = document.getElementById('output-canvas');
var zoomFactor = parseInt(document.getElementById('zoom-factor').value);
var zoomedCanvas = document.createElement('canvas');
zoomedCanvas.width = outputCanvas.width * zoomFactor;
zoomedCanvas.height = outputCanvas.height * zoomFactor;
var ctx = zoomedCanvas.getContext('2d');
ctx.drawImage(outputCanvas, 0, 0,
outputCanvas.width, outputCanvas.height, 0, 0,
zoomedCanvas.width, zoomedCanvas.height
);
zoomedCanvas.toBlob(function (blob) {
var item = new ClipboardItem({"image/png": blob});
navigator.clipboard.write([item]).then(function () {
alert('Zoomed image copied to clipboard!');
}).catch(function (err) {
console.error('Failed to copy: ', err);
});
}, 'image/png');
}
function getMedianColor(ctx, x, y, scale, imgData) {
var pixelCount = scale * scale;
var colors = [0, 0, 0];
var r = 0;
var g = 0;
var b = 0;
for (var j = y; j < y + scale; j++) {
for (var i = x; i < x + scale; i++) {
const index = (j * ctx.canvas.width + i) * 4;
r += imgData.data[index + 0];
g += imgData.data[index + 1];
b += imgData.data[index + 2];
}
}
return [r, g, b].map(function (c) {return Math.round(c / pixelCount);});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment