Files
StarPilot/openpilot/starpilot/galaxy/web/js/widget-art.js
T
firestar5683 fab3ec9aeb Galaxy UI
Add Galaxy web assets and client settings interfaces with their bundled vendor notices.

Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>

Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com>
Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 19:56:17 -05:00

36 lines
2.2 KiB
JavaScript

// Pixels and sprite locations come from the actual onroad renderer, not browser widget copies.
export async function widgetArtMetadata(blob) {
const bytes = new Uint8Array(await blob.arrayBuffer())
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
if (bytes.length < 45 || bytes.length > 4 * 1024 * 1024 ||
![137,80,78,71,13,10,26,10].every((value, index) => bytes[index] === value)) throw new Error("Invalid widget art")
const text = new TextDecoder(), signature = "starpilot-widget-art\0"
let metadata = null
for (let offset = 8; offset + 12 <= bytes.length;) {
const size = view.getUint32(offset), type = text.decode(bytes.subarray(offset + 4, offset + 8))
if (size > bytes.length - offset - 12) throw new Error("Invalid widget art chunk")
if (type === "tEXt") {
const value = text.decode(bytes.subarray(offset + 8, offset + 8 + size))
if (value.startsWith(signature)) {
if (metadata || size > 8192) throw new Error("Invalid widget art metadata")
metadata = JSON.parse(value.slice(signature.length))
}
}
offset += size + 12
}
if (!metadata || metadata.version !== 1 || !Number.isInteger(metadata.width) || !Number.isInteger(metadata.height) ||
metadata.width < 1 || metadata.width > 1024 || metadata.height < 1 || metadata.height > 1440 ||
metadata.width !== view.getUint32(16) || metadata.height !== view.getUint32(20) ||
!metadata.sprites || typeof metadata.sprites !== "object" || Array.isArray(metadata.sprites) ||
Object.keys(metadata.sprites).length > 7) throw new Error("Invalid widget art metadata")
for (const [id, rect] of Object.entries(metadata.sprites)) {
if (!/^[a-z_]+$/.test(id) || !rect || ![rect.x,rect.y,rect.width,rect.height].every(Number.isInteger) ||
rect.x < 0 || rect.y < 0 || rect.width < 1 || rect.height < 1 ||
rect.x + rect.width > metadata.width || rect.y + rect.height > metadata.height ||
!Number.isFinite(rect.offsetX ?? 0) || (rect.offsetX ?? 0) <= -1 || (rect.offsetX ?? 0) > 0 ||
!Number.isFinite(rect.offsetY ?? 0) || (rect.offsetY ?? 0) <= (id === 'speed_limit_actions' ? -33 : -1) ||
(rect.offsetY ?? 0) > 0) throw new Error("Invalid widget art rectangle")
}
return metadata
}