66 lines
1.7 KiB
TypeScript
66 lines
1.7 KiB
TypeScript
import type { TileAnalysisResult } from '@/types/tileTypes'
|
|
|
|
const PIXEL_SAMPLE_RATE = 4
|
|
|
|
self.onmessage = async (e: MessageEvent) => {
|
|
const { imageData, tileId, tileName } = e.data
|
|
const result = analyzeTile(imageData, tileId, tileName)
|
|
self.postMessage(result)
|
|
}
|
|
|
|
function analyzeTile(imageData: ImageData, tileId: string, tileName: string): TileAnalysisResult {
|
|
const { r, g, b } = getDominantColorFast(imageData)
|
|
const edge = getEdgeComplexityFast(imageData)
|
|
const namePrefix = tileName.split('_')[0]
|
|
return {
|
|
tileId,
|
|
color: { r, g, b },
|
|
edge,
|
|
namePrefix
|
|
}
|
|
}
|
|
|
|
function getDominantColorFast(imageData: ImageData) {
|
|
const data = new Uint8ClampedArray(imageData.data.buffer)
|
|
let r = 0,
|
|
g = 0,
|
|
b = 0,
|
|
total = 0
|
|
const length = data.length
|
|
|
|
for (let i = 0; i < length; i += 4 * PIXEL_SAMPLE_RATE) {
|
|
if (data[i + 3] > 0) {
|
|
r += data[i]
|
|
g += data[i + 1]
|
|
b += data[i + 2]
|
|
total++
|
|
}
|
|
}
|
|
|
|
return total > 0
|
|
? {
|
|
r: Math.round(r / total),
|
|
g: Math.round(g / total),
|
|
b: Math.round(b / total)
|
|
}
|
|
: { r: 0, g: 0, b: 0 }
|
|
}
|
|
|
|
function getEdgeComplexityFast(imageData: ImageData) {
|
|
const data = new Uint8ClampedArray(imageData.data.buffer)
|
|
const width = imageData.width
|
|
const height = imageData.height
|
|
let edgePixels = 0
|
|
|
|
// Only check every other row/column
|
|
for (let y = 0; y < height; y += PIXEL_SAMPLE_RATE * 2) {
|
|
for (let x = 0; x < width; x += PIXEL_SAMPLE_RATE * 2) {
|
|
const i = (y * width + x) * 4
|
|
if (data[i + 3] > 0 && (x === 0 || y === 0 || x >= width - PIXEL_SAMPLE_RATE || y >= height - PIXEL_SAMPLE_RATE || data[i - 4 * PIXEL_SAMPLE_RATE + 3] === 0)) {
|
|
edgePixels++
|
|
}
|
|
}
|
|
}
|
|
return edgePixels * PIXEL_SAMPLE_RATE * 2
|
|
}
|