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