Add a icon rendering API
This commit is contained in:
99
src/routes/berrydash/render-icon/get.ts
Normal file
99
src/routes/berrydash/render-icon/get.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
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' }
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user