Files
api/src/routes/berrydash/render-icon/get.ts
2026-02-16 23:40:21 -07:00

100 lines
2.6 KiB
TypeScript

import { Context } from 'elysia'
import axios from 'axios'
import sharp from 'sharp'
const parseIntParam = (value: string): number | null => {
const parsed = Number(value)
if (isNaN(parsed)) return null
return parsed
}
const clamp = (n: number): number => Math.max(0, Math.min(255, n))
const recolor = async (imgBuffer: Buffer, color: number[]): Promise<Buffer> => {
const [r, g, b] = color
const image = sharp(imgBuffer)
const raw = await image
.ensureAlpha()
.raw()
.toBuffer({ resolveWithObject: true })
const pixels = raw.data
const { width: w, height: h } = raw.info
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = Math.round((pixels[i] / 255) * r)
pixels[i + 1] = Math.round((pixels[i + 1] / 255) * g)
pixels[i + 2] = Math.round((pixels[i + 2] / 255) * b)
}
return sharp(pixels, {
raw: { width: w, height: h!, channels: 4 }
})
.png()
.toBuffer()
}
export const handler = async (context: Context) => {
let icon = Math.max(-4, Math.min(8, parseIntParam(context.query.icon) ?? 1))
let overlay = Math.max(
0,
Math.min(14, parseIntParam(context.query.overlay) ?? 0)
)
const birdColor = [
clamp(parseIntParam(context.query.birdR) ?? 255),
clamp(parseIntParam(context.query.birdG) ?? 255),
clamp(parseIntParam(context.query.birdB) ?? 255)
]
const overlayColor = [
clamp(parseIntParam(context.query.overlayR) ?? 255),
clamp(parseIntParam(context.query.overlayG) ?? 255),
clamp(parseIntParam(context.query.overlayB) ?? 255)
]
let overlayImg: Buffer | null = null
let iconImg: Buffer | null = null
if (overlay !== 0) {
try {
const result = await axios.get(
`https://games-r2.lncvrt.xyz/game-assets/berrydash/overlays/overlay_${overlay}.png`,
{ responseType: 'arraybuffer' }
)
overlayImg = Buffer.from(result.data)
} catch {}
}
try {
const result = await axios.get(
`https://games-r2.lncvrt.xyz/game-assets/berrydash/icons/bird_${icon}.png`,
{ responseType: 'arraybuffer' }
)
iconImg = Buffer.from(result.data)
} catch {}
if (!iconImg) {
return new Response(null, { status: 400 })
}
let result = await recolor(iconImg, birdColor)
if (overlayImg) {
const recoloredOverlay = await recolor(overlayImg, overlayColor)
result = await sharp(result)
.composite([
{
input: recoloredOverlay,
top: overlay == 8 ? 25 : 13,
left: overlay == 8 ? 10 : 15,
blend: 'over'
}
])
.png()
.toBuffer()
}
return new Response(result.buffer as ArrayBuffer, {
headers: { 'Content-Type': 'image/png' }
})
}