(async () => { | |
const rows = 44 | |
const cols = 36 | |
const fps = 12 | |
const gif = "http://i.imgur.com/ifR7csn.gif" | |
const rotate = false | |
const mirror = false | |
const vertmirror = false | |
document.body.innerHTML = '' | |
document.body.style = 'margin: 0; background: palegoldenrod; display: flex; flex-direction: column; justify-content: center; align-items: center;' | |
const canvas = document.createElement('canvas') | |
canvas.style = 'width: 360px; height: 440px; image-rendering: pixelated; transform: scaleY(-1);' | |
canvas.width = cols | |
canvas.height = rows | |
const ctx = canvas.getContext('2d') | |
window.ctx = ctx | |
document.body.appendChild(canvas) | |
const textarea = document.createElement('textarea') | |
textarea.addEventListener('click', textarea.select) | |
textarea.style = 'height: 100px; width: 360px;' | |
const button = document.createElement('button') | |
button.type = button | |
button.disabled = true | |
button.innerHTML = "Loading X-GIF..." | |
const link = document.createElement('link'); | |
link.rel = 'import'; | |
link.href = 'http://geelen.github.io/x-gif/dist/x-gif.html'; | |
link.setAttribute('async', true); // make it async! | |
const loaded = new Promise(res => link.onload = res) | |
document.head.appendChild(link) | |
await loaded | |
button.innerHTML = "Loading gif..." | |
const xgif = document.createElement('x-gif') | |
xgif.setAttribute('src', gif) | |
await xgif.controller.playback.ready | |
// document.body.appendChild(xgif) | |
console.log(xgif) | |
button.addEventListener('click', () => { | |
textarea.value = 'Rendering string...\n(This can take a while)\n(Your browser will lock up)\n(#sorrynotsorry)' | |
document.body.appendChild(textarea) | |
button.style.display = 'none' | |
setTimeout(done, 100) | |
}) | |
document.body.appendChild(button) | |
button.innerHTML = "Animating..." | |
const frames = [] | |
let frameNr = 0 | |
const gif_frames = xgif.shadowRoot.querySelectorAll('img') | |
ctx.fillStyle = 'black' | |
ctx.fillRect(0,0, canvas.width, canvas.height) | |
if (window.lastTimeout) clearTimeout(window.lastTimeout) | |
const draw = () => { | |
if (xgif.controller.playback.gif.frames[frameNr].disposal === 2) { | |
ctx.fillRect(0,0, canvas.width, canvas.height) | |
} | |
// RENDER SOMETHING TO CANVAS | |
if (mirror) { | |
ctx.save() | |
ctx.translate(cols, 0) | |
ctx.rotate(Math.PI / 2) | |
ctx.drawImage(gif_frames[frameNr], 0 - 20, cols / 2, rows + 50, cols / 2 + 8) | |
ctx.restore() | |
ctx.save() | |
ctx.translate(cols / 2, 0) | |
ctx.rotate(Math.PI / 2) | |
ctx.scale(1, -1) | |
ctx.drawImage(gif_frames[frameNr], 0 - 20, 0, rows + 50, cols / 2 + 8) | |
ctx.restore() | |
} | |
else if (rotate) { | |
ctx.save() | |
ctx.translate(cols, 0) | |
ctx.rotate(Math.PI / 2) | |
ctx.drawImage(gif_frames[frameNr], 0, 0, rows, cols) | |
ctx.restore() | |
} else if (vertmirror) { | |
ctx.save() | |
ctx.translate(0, rows) | |
ctx.scale(1, -1) | |
ctx.drawImage(gif_frames[frameNr], 0, 0, cols, rows) | |
ctx.restore() | |
} else { | |
ctx.drawImage(gif_frames[frameNr], 0, 0, cols, rows) | |
} | |
// OK STOP NOW THANKS | |
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height) | |
const rgbData = [] | |
imageData.data.forEach((x,i) => { | |
if (i % 4 !== 3) rgbData.push(x) | |
}) | |
frames.push(rgbData) | |
if (frameNr < gif_frames.length - 1) { | |
window.lastTimeout = setTimeout(draw, Math.round(1000 / fps)) | |
} else { | |
button.innerHTML = 'Render string' | |
button.disabled = false | |
} | |
frameNr++ | |
} | |
draw() | |
function done() { | |
const str = | |
`const frames_str = [ | |
${frames.map(frame => `"${btoa(frame.map(x => String.fromCharCode(x)).join(''))}"`).join(',\n')} | |
] | |
const frames = frames_str.map(str => { | |
const binstr = atob(str) | |
return [...binstr].map(char => char.charCodeAt(0)) | |
}) | |
export function transform(buffer, rows, cols, frameCount, fps, isFirst) { | |
const frameSize = 3 * rows * cols | |
const lineSize = cols * 3 | |
for (let i = 0; i < frameCount; i++) { | |
const frame = new Uint8Array(buffer, frameSize * i, frameSize) | |
const texture = frames[Math.floor(i/${35/fps}) % frames.length] | |
for (let j = 0; j < rows; j++) { | |
const line = frame.subarray(lineSize * j, lineSize* (j + 1)); | |
for (let k = 0; k < cols; k++) { | |
line[k * 3 + 0] = texture[j * cols * 3 + k * 3 + 0] | |
line[k * 3 + 1] = texture[j * cols * 3 + k * 3 + 1] | |
line[k * 3 + 2] = texture[j * cols * 3 + k * 3 + 2] | |
} | |
} | |
} | |
} | |
export default function () { | |
return Promise.resolve({ | |
transform, | |
}) | |
} | |
` | |
textarea.value = str | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment