Almost
This commit is contained in:
parent
eaa7385acc
commit
c400e868af
@ -5,12 +5,20 @@ import { SpriteAction } from '#entities/spriteAction'
|
||||
import sharp from 'sharp'
|
||||
import fs from 'fs'
|
||||
|
||||
interface SpriteImage {
|
||||
url: string
|
||||
offset: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
}
|
||||
|
||||
type Payload = {
|
||||
id: UUID
|
||||
name: string
|
||||
spriteActions: Array<{
|
||||
action: string
|
||||
sprites: string[]
|
||||
sprites: SpriteImage[]
|
||||
originX: number
|
||||
originY: number
|
||||
frameRate: number
|
||||
@ -74,12 +82,12 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
}
|
||||
}
|
||||
|
||||
private async calculateMaxWidth(sprites: string[]): Promise<number> {
|
||||
private async calculateMaxWidth(sprites: SpriteImage[]): Promise<number> {
|
||||
if (!sprites.length) return 0
|
||||
|
||||
const widths = await Promise.all(
|
||||
sprites.map(async (base64) => {
|
||||
const uri = base64.split(';base64,').pop()
|
||||
const uri = base64.url.split(';base64,').pop()
|
||||
if (!uri) return 0
|
||||
|
||||
const imgBuffer = Buffer.from(uri, 'base64')
|
||||
@ -91,12 +99,12 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
return Math.max(...widths)
|
||||
}
|
||||
|
||||
private async calculateMaxHeight(sprites: string[]): Promise<number> {
|
||||
private async calculateMaxHeight(sprites: SpriteImage[]): Promise<number> {
|
||||
if (!sprites.length) return 0
|
||||
|
||||
const heights = await Promise.all(
|
||||
sprites.map(async (base64) => {
|
||||
const uri = base64.split(';base64,').pop()
|
||||
const uri = base64.url.split(';base64,').pop()
|
||||
if (!uri) return 0
|
||||
|
||||
const imgBuffer = Buffer.from(uri, 'base64')
|
||||
@ -108,46 +116,69 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
return Math.max(...heights)
|
||||
}
|
||||
|
||||
private async generateSpriteSheet(sprites: string[], spriteId: string, action: string): Promise<boolean> {
|
||||
private async generateSpriteSheet(sprites: SpriteImage[], spriteId: string, action: string): Promise<boolean> {
|
||||
try {
|
||||
// Skip if no sprites
|
||||
if (!sprites.length) return true
|
||||
|
||||
// Process all base64 images to buffers and get their dimensions
|
||||
const imageData = await Promise.all(
|
||||
sprites.map(async (base64) => {
|
||||
const uri = base64.split(';base64,').pop()
|
||||
sprites.map(async (sprite) => {
|
||||
const uri = sprite.url.split(';base64,').pop()
|
||||
if (!uri) throw new Error('Invalid base64 image')
|
||||
const buffer = Buffer.from(uri, 'base64')
|
||||
const metadata = await sharp(buffer).metadata()
|
||||
return { buffer, width: metadata.width ?? 0, height: metadata.height ?? 0 }
|
||||
return {
|
||||
buffer,
|
||||
width: metadata.width ?? 0,
|
||||
height: metadata.height ?? 0,
|
||||
offsetX: sprite.offset?.x ?? 0,
|
||||
offsetY: sprite.offset?.y ?? 0
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// Find the largest dimensions
|
||||
const maxWidth = Math.max(...imageData.map((data) => data.width))
|
||||
const maxHeight = Math.max(...imageData.map((data) => data.height))
|
||||
// Find the largest dimensions including offsets
|
||||
const effectiveDimensions = imageData.map(({ width, height, offsetX, offsetY }) => ({
|
||||
width: width + Math.abs(offsetX),
|
||||
height: height + Math.abs(offsetY),
|
||||
top: offsetY >= 0 ? offsetY : 0,
|
||||
bottom: offsetY < 0 ? Math.abs(offsetY) : 0
|
||||
}))
|
||||
const maxWidth = Math.max(...effectiveDimensions.map(d => d.width))
|
||||
const maxHeight = Math.max(...effectiveDimensions.map(d => d.height))
|
||||
const maxTop = Math.max(...effectiveDimensions.map(d => d.top))
|
||||
const maxBottom = Math.max(...effectiveDimensions.map(d => d.bottom))
|
||||
|
||||
console.log(maxWidth, maxHeight)
|
||||
// Calculate total height needed to accommodate all sprites with their offsets
|
||||
const totalHeight = maxHeight + maxTop + maxBottom
|
||||
|
||||
// Extend all images to match the largest dimensions without resizing
|
||||
const resizedBuffers = await Promise.all(
|
||||
imageData.map(async ({ buffer, width, height }) => {
|
||||
// Calculate padding to center the sprite
|
||||
const topPadding = 0 // This is always 0. We don't need to calculate it
|
||||
const bottomPadding = Math.ceil((maxHeight - height) / 2)
|
||||
const leftPadding = Math.ceil((maxWidth - width) / 2)
|
||||
const rightPadding = Math.ceil((maxWidth - width) / 2)
|
||||
imageData.map(async ({ buffer, width, height, offsetX, offsetY }) => {
|
||||
// Calculate the position of the image within the frame
|
||||
const left = offsetX >= 0 ? offsetX : 0
|
||||
// Position from bottom edge while respecting offsetY
|
||||
const verticalOffset = totalHeight - height - (offsetY >= 0 ? offsetY : 0)
|
||||
|
||||
return await sharp(buffer)
|
||||
.extend({
|
||||
top: topPadding,
|
||||
bottom: bottomPadding,
|
||||
left: leftPadding,
|
||||
right: rightPadding,
|
||||
// Create a blank canvas of the maximum size
|
||||
return await sharp({
|
||||
create: {
|
||||
width: maxWidth,
|
||||
height: totalHeight,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
||||
})
|
||||
.toBuffer()
|
||||
}
|
||||
})
|
||||
.composite([
|
||||
{
|
||||
input: buffer,
|
||||
left: left,
|
||||
top: verticalOffset
|
||||
}
|
||||
])
|
||||
.png()
|
||||
.toBuffer()
|
||||
})
|
||||
)
|
||||
|
||||
@ -155,7 +186,7 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
const spriteSheet = await sharp({
|
||||
create: {
|
||||
width: maxWidth * sprites.length,
|
||||
height: maxHeight,
|
||||
height: totalHeight,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user