Skip to content

Instantly share code, notes, and snippets.

@CarterLi CarterLi/canvas.html
Created Jun 29, 2017

Embed
What would you like to do?
canvas
<!doctype html>
<meta charset="utf-8" />
<style type="text/css">
canvas {
display: block;
}
</style>
<input id="file" type="file" accept="image/*" multiple />
<canvas id="canvas"></canvas>
<script>
/**
* @param {string} url
* @return {Promise<HTMLImageElement>}
*/
function loadImageFromUrl(url) {
return new Promise(resolve => {
const image = new Image();
image.crossOrigin = 'Anonymous';
image.addEventListener('load', function (e) {
resolve(image);
}, { once: true });
image.src = url;
});
}
/**
* @param {File} file
* @return {Promise<string>}
*/
function loadUrlFromFile(file) {
return new Promise(resolve => {
const reader = new FileReader();
reader.addEventListener('load', function (e) {
resolve(reader.result);
}, { once: true });
reader.readAsDataURL(file);
});
}
/**
* @param {ImageData} imgData
* @param {number} length
*/
function createMosaic(imgData, length) {
for (let row = 0; row < imgData.height; row += length) {
for (let column = 0; column < imgData.width; column += length) {
const index = (row * imgData.width + column) * 4;
for (let x = column + 1; x < column + length; ++x) {
const targetIndex = (row * imgData.width + x) * 4;
imgData.data.copyWithin(targetIndex, index, index + 4);
}
for (let y = row + 1; y < row + length; ++y) {
const targetIndex = (y * imgData.width + column) * 4;
imgData.data.copyWithin(targetIndex, index, index + length * 4);
}
}
}
return imgData;
}
/**
* @type {HTMLCanvasElement}
*/
const canvas = document.getElementById('canvas');
/**
* @type {HTMLInputElement}
*/
const file = document.getElementById('file');
file.addEventListener('change', async function (e) {
const file = this.files[0];
const url = await loadUrlFromFile(file);
const image = await loadImageFromUrl(url);
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const originalData = new Uint8ClampedArray(imgData.data);
let start = 0, lastLength, flag = false;
function render(t) {
imgData.data.set(originalData);
start = start || t;
const percent = Math.min(1, (t - start) / 2000);
let length = ~~(canvas.width / 10 * (flag ? 1 - percent : percent) ** 3);
if (lastLength !== length) {
if (length < 2) {
ctx.putImageData(imgData, 0, 0);
} else {
ctx.putImageData(createMosaic(imgData, length), 0, 0);
}
lastLength = length;
}
requestAnimationFrame(render);
if (percent === 1) {
flag = !flag;
start = t;
}
}
requestAnimationFrame(render);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.