Skip to content

Instantly share code, notes, and snippets.

@WietseWind
Last active August 27, 2022 00:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WietseWind/720e90345d6a34204372307b9a9c9670 to your computer and use it in GitHub Desktop.
Save WietseWind/720e90345d6a34204372307b9a9c9670 to your computer and use it in GitHub Desktop.
Tidbyt SVG to GIF with NodeJS
import express from 'express'
import sharp from 'sharp'
import fetch from 'node-fetch'
sharp.cache(false)
const app = express()
const port = 3000
const device = 'some-device-name-whatever-123'
const apikey = 'some.jwt.string'
const render = async res => {
const composites = []
const svg = `
<svg width="64" fill="orange" height="32" viewBox="0 0 64 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="crispify">
<feComponentTransfer>
<feFuncA type="discrete" tableValues="0 1"/>
</feComponentTransfer>
</filter>
</defs>
<rect stroke-width="0" fill="navy" x="0" y="0" width="64" height="32" rx="5"></rect>
<rect stroke-width="3" stroke="white" fill="purple" x="4" y="5" width="10" height="10" rx="5"></rect>
<text filter="url(#crispify)" text-anchor="middle" x="40" y="11" fill="white" style="font-family: JetBrains Mono; font-weight: 600; font-size: 10px">
123.998
</text>
<text filter="url(x#crispify)" text-anchor="middle" x="32" y="30" fill="white" style="font-family: Arial; font-weight: 400; font-size: 15px">
Hi you!
</text>
</svg>
`
composites.push({ input: Buffer.from(svg), top: 0, left: 0 })
const output =
await sharp({ create: { width: 64, height: 32, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 1 }, } })
.ensureAlpha().composite(composites).gif().toBuffer()
const buf = Buffer.from(output, 'binary')
res?.setHeader('Content-Type', 'image/gif')
// Update the brightness (for later, TODO, programmatically based on time of day)
await fetch('https://api.tidbyt.com/v0/devices/' + device, {
method: 'PATCH', headers: { 'Content-type': 'application/json', 'Authorization': 'Bearer ' + apikey },
body: JSON.stringify({ brightness: 20, autoDim: false, })
})
// Set the image
const f = await fetch('https://api.tidbyt.com/v0/devices/' + device + '/push', {
method: 'POST',
headers: { 'Content-type': 'application/json', 'Authorization': 'Bearer ' + apikey },
body: JSON.stringify({ image: buf.toString('base64'), background: false, installationID: 'nodejs', })
})
console.log('Rendered & live', await f.json())
return buf
}
app.get('/', async (req, res) => {
// Render on HTTP refresh
res.send(Buffer.from(await render(res), 'binary'))
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
// Render when app starts
render()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment