Skip to content

Instantly share code, notes, and snippets.

@usame-algan
Last active June 2, 2023 10:27
Show Gist options
  • Save usame-algan/d7adfe4be1008568274714cb8d22b216 to your computer and use it in GitHub Desktop.
Save usame-algan/d7adfe4be1008568274714cb8d22b216 to your computer and use it in GitHub Desktop.
Obfuscate/Blur element
type Color = { r: number, g: number, b: number, a: number }
// Helpers
function getTextBoundingBox(ctx: CanvasRenderingContext2D, text: string) {
const metrics = ctx.measureText(text)
const top = metrics.actualBoundingBoxAscent * -1
const bottom = metrics.actualBoundingBoxDescent
const height = bottom - top
return { top, height }
}
function getAverageColor(imageData: Uint8ClampedArray): Color {
let r = 0,
g = 0,
b = 0,
a = 0,
count = 0
for (let i = 0; i < imageData.length; i += 4) {
r += imageData[i]
g += imageData[i + 1]
b += imageData[i + 2]
a += imageData[i + 3]
count++
}
r /= count
g /= count
b /= count
a /= count
a = a / 100
return {r,g,b,a}
}
function createMosaicBlock(x: number, y: number, cellSize: number, color: Color) {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('x', x.toString())
rect.setAttribute('y', y.toString())
rect.setAttribute('width', cellSize.toString())
rect.setAttribute('height', cellSize.toString())
rect.setAttribute('fill', `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a.toFixed(2)})`)
return rect
}
function createCanvas(element: HTMLElement) {
const canvas = document.createElement('canvas')
canvas.width = element.offsetWidth
canvas.height = element.offsetHeight
const ctx = canvas.getContext('2d', {willReadFrequently: true})
if (!ctx) return {}
const textStyle = getComputedStyle(element)
ctx.textBaseline = 'top'
ctx.font = textStyle.font
ctx.fillStyle = textStyle.color
const { top, height } = getTextBoundingBox(ctx, element.innerText)
const middle_y = top + height / 2
const offsetTop = canvas.height / 2 - middle_y
// Draw the text onto the canvas
ctx.fillText(element.innerText, 0, offsetTop)
return { canvas, ctx }
}
function createSVG(element: HTMLElement) {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute('width', element.offsetWidth.toString())
svg.setAttribute('height', element.offsetHeight.toString())
return svg
}
/**
* Visually blur/obfuscate the contents of an element
* 123$ -> ◼◽◾
*/
function obfuscateElement(element: HTMLElement) {
const { canvas, ctx } = createCanvas(element)
if (!canvas || !ctx) throw Error("Could not create canvas")
const svg = createSVG(element)
const cellSize = element.offsetHeight / 2
for (let x = 0; x < canvas.width; x += cellSize) {
for (let y = 0; y < canvas.height; y += cellSize) {
const imageData = ctx.getImageData(x, y, cellSize, cellSize).data
const color = getAverageColor(imageData)
const mosaic = createMosaicBlock(x, y, cellSize, color)
svg.appendChild(mosaic)
}
}
return svg
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment