100 lines
2.6 KiB
TypeScript
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' }
|
|
})
|
|
}
|