Skip to content

Instantly share code, notes, and snippets.

@geelen
Last active June 3, 2018 14:06
Show Gist options
  • Save geelen/f33a8f7a17d776265fff6de05d190f4b to your computer and use it in GitHub Desktop.
Save geelen/f33a8f7a17d776265fff6de05d190f4b to your computer and use it in GitHub Desktop.
(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