From 96c7b541a435ea1d3da208a572dd4b5f6b7dde70 Mon Sep 17 00:00:00 2001
From: fpv-wtf <>
Date: Thu, 16 May 2024 11:04:50 +0000
Subject: [PATCH] Update from
https://github.com/fpv-wtf/wtfos-configurator/commit/d45f3224a44365362a11673d3733a567e55ae300
---
src/features/osd-overlay/FileDrop.jsx | 42 ++++-----------
src/features/osd-overlay/OsdOverlay.jsx | 10 +---
src/osd-overlay/fonts.ts | 71 +++++++++++++++----------
src/osd-overlay/osd.ts | 60 ++++++++++++++++++++-
src/osd-overlay/worker.ts | 15 ++----
src/translations/en/osdOverlay.json | 2 +
6 files changed, 120 insertions(+), 80 deletions(-)
diff --git a/src/features/osd-overlay/FileDrop.jsx b/src/features/osd-overlay/FileDrop.jsx
index 7c32f98..f617ff4 100644
--- a/src/features/osd-overlay/FileDrop.jsx
+++ b/src/features/osd-overlay/FileDrop.jsx
@@ -16,10 +16,8 @@ import FileDropEntry from "./FileDropEntry";
export function useFileDropState() {
const [files, setFiles] = React.useState({
- fontFileHd1: null,
- fontFileHd2: null,
- fontFileSd1: null,
- fontFileSd2: null,
+ fontFileHd: null,
+ fontFileSd: null,
osdFile: null,
srtFile: null,
videoFile: null,
@@ -60,19 +58,11 @@ export default function FileDrop(props) {
changedFiles.srtFile = file;
break;
- case "bin":
+ case "png":
if (name.includes("hd")) {
- if (name.includes("_2")) {
- changedFiles.fontFileHd2 = file;
- } else {
- changedFiles.fontFileHd1 = file;
- }
+ changedFiles.fontFileHd = file;
} else {
- if (name.includes("_2")) {
- changedFiles.fontFileSd2 = file;
- } else {
- changedFiles.fontFileSd1 = file;
- }
+ changedFiles.fontFileSd = file;
}
break;
@@ -126,7 +116,7 @@ export default function FileDrop(props) {
}}
>
-
-
-
-
diff --git a/src/features/osd-overlay/OsdOverlay.jsx b/src/features/osd-overlay/OsdOverlay.jsx
index f84b70b..9a9f147 100644
--- a/src/features/osd-overlay/OsdOverlay.jsx
+++ b/src/features/osd-overlay/OsdOverlay.jsx
@@ -30,10 +30,8 @@ export default function OsdOverlay() {
const osdFile = files.osdFile;
const srtFile = files.srtFile;
const fontFiles = React.useMemo(() => ({
- sd1: files.fontFileSd1,
- sd2: files.fontFileSd2,
- hd1: files.fontFileHd1,
- hd2: files.fontFileHd2,
+ sd: files.fontFileSd,
+ hd: files.fontFileHd,
}), [files]);
const [progress, setProgress] = React.useState(0);
@@ -69,10 +67,6 @@ export default function OsdOverlay() {
const startEnabled = (
videoFile &&
osdFile &&
- fontFiles.sd1 &&
- fontFiles.sd2 &&
- fontFiles.hd1 &&
- fontFiles.hd2 &&
!inProgress
);
const progressValue = progressMax ? (progress / progressMax) * 100 : 0;
diff --git a/src/osd-overlay/fonts.ts b/src/osd-overlay/fonts.ts
index e150fe9..09e5516 100644
--- a/src/osd-overlay/fonts.ts
+++ b/src/osd-overlay/fonts.ts
@@ -1,3 +1,4 @@
+import { OsdReader } from "./osd";
export const SD_TILE_WIDTH = 12 * 3;
export const SD_TILE_HEIGHT = 18 * 3;
@@ -7,17 +8,13 @@ export const HD_TILE_HEIGHT = 18 * 2;
export const TILES_PER_PAGE = 256;
export interface FontPack {
- sd1: Font;
- sd2: Font;
- hd1: Font;
- hd2: Font;
+ sd: Font;
+ hd: Font;
}
export interface FontPackFiles {
- sd1: File;
- sd2: File;
- hd1: File;
- hd2: File;
+ sd: File;
+ hd: File;
}
export class Font {
@@ -33,35 +30,53 @@ export class Font {
return this.tiles[index];
}
- static async fromFile(file: File): Promise {
- const data = await file.arrayBuffer();
- const isHd = file.name.includes("hd");
+ static async fromFile(file: File, isHd : boolean, reader: OsdReader): Promise {
+ const [filename, data] = await (async (file : File) => {
+ if (file && file.size > 0) {
+ return [file.name, await file.arrayBuffer()];
+ } else {
+ const font_filename = `font_${reader.header.config.fontVariant.toLowerCase()}${isHd ? "_hd" : ""}.png`;
+ return ["font_filename", await fetch(`https://raw.githubusercontent.com/fpv-wtf/msp-osd/main/fonts/${font_filename}`).then((response) => response.arrayBuffer())];
+ }
+ })(file);
const tileWidth = isHd ? HD_TILE_WIDTH : SD_TILE_WIDTH;
const tileHeight = isHd ? HD_TILE_HEIGHT : SD_TILE_HEIGHT;
- const tiles: ImageBitmap[] = [];
- for (let tileIndex = 0; tileIndex < TILES_PER_PAGE; tileIndex++) {
- const pixData = new Uint8ClampedArray(
- data,
- tileIndex * tileWidth * tileHeight * 4,
- tileWidth * tileHeight * 4
- );
-
- const imageData = new ImageData(pixData, tileWidth, tileHeight);
- const imageBitmap = await createImageBitmap(imageData);
- tiles.push(imageBitmap);
+ // Create an image bitmap from the ArrayBuffer
+ const imageBitmap = await createImageBitmap(new Blob([data]));
+
+ const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height);
+ const context = canvas.getContext("2d");
+
+ if (!context) {
+ throw new Error("2D context not supported or canvas creation failed");
+ }
+
+ context.drawImage(imageBitmap, 0, 0);
+
+ const tiles = [];
+ const tilesPerColumn = TILES_PER_PAGE; // Number of tiles per column
+ const columns = imageBitmap.width / tileWidth; // Number of columns
+
+ for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
+ for (let rowIndex = 0; rowIndex < tilesPerColumn; rowIndex++) {
+ const x = columnIndex * tileWidth; // x-coordinate based on column
+ const y = rowIndex * tileHeight; // y-coordinate based on row
+
+ const imageData = context.getImageData(x, y, tileWidth, tileHeight);
+ const tileBitmap = await createImageBitmap(imageData);
+ tiles.push(tileBitmap);
+ }
}
- return new Font(file.name, tiles);
+ return new Font(filename, tiles);
}
- static async fromFiles(files: FontPackFiles): Promise {
+ static async fromFiles(files: FontPackFiles, reader: OsdReader): Promise {
return {
- sd1: await Font.fromFile(files.sd1),
- sd2: await Font.fromFile(files.sd2),
- hd1: await Font.fromFile(files.hd1),
- hd2: await Font.fromFile(files.hd2),
+ sd: await Font.fromFile(files.sd, false, reader),
+ hd: await Font.fromFile(files.hd, true, reader),
};
}
}
diff --git a/src/osd-overlay/osd.ts b/src/osd-overlay/osd.ts
index 284c9c1..7cc3918 100644
--- a/src/osd-overlay/osd.ts
+++ b/src/osd-overlay/osd.ts
@@ -7,6 +7,22 @@ interface OsdHeader {
}
interface OsdConfig {
+ charWidth: number;
+ charHeight: number;
+ fontWidth: number;
+ fontHeight: number;
+ xOffset: number;
+ yOffset: number;
+ fontVariant: string;
+}
+
+interface OsdHeaderV1 {
+ magic: string;
+ version: number;
+ config: OsdConfigV1;
+}
+
+interface OsdConfigV1 {
charWidth: number;
charHeight: number;
fontWidth: number;
@@ -38,10 +54,52 @@ export class OsdReader {
fontHeight: stream.getNextUint8(),
xOffset: stream.getNextUint16(),
yOffset: stream.getNextUint16(),
- fontVariant: stream.getNextUint8(),
+ fontVariant: stream.getNextString(5).substring(0, 4), // read 5 bytes, keep 4. string is from c; null terminated. reading all 5 leaves pointer in right place to start reading frames below
},
};
+ // v1 of this format used a slightly different structure - fontVariant was a number, not a string
+ // in msp-osd itself an enum was used to store the FC variant, which became the number we have here
+ // since msp-osd 0.12 we use the FC identifier internally (so we don't need to rely on the magic enum)
+ // this maps the legacy enum to the correct string identifier, as well as leaving the file pointer
+ // in the correct place for a legacy file
+ if (this.header.version === 1) {
+ stream.resetOffset();
+ const tempheader : OsdHeaderV1 = {
+ magic: stream.getNextString(7),
+ version: stream.getNextUint16(),
+ config: {
+ charWidth: stream.getNextUint8(),
+ charHeight: stream.getNextUint8(),
+ fontWidth: stream.getNextUint8(),
+ fontHeight: stream.getNextUint8(),
+ xOffset: stream.getNextUint16(),
+ yOffset: stream.getNextUint16(),
+ fontVariant: stream.getNextUint8(),
+ },
+ };
+
+ switch (tempheader.config.fontVariant) {
+ case 1: // FONT_VARIANT_BETAFLIGHT
+ this.header.config.fontVariant = "BTFL";
+ break;
+ case 2: // FONT_VARIANT_INAV
+ this.header.config.fontVariant = "INAV";
+ break;
+ case 3: // FONT_VARIANT_ARDUPILOT
+ this.header.config.fontVariant = "ARDU";
+ break;
+ case 4: // FONT_VARIANT_KISS_ULTRA
+ this.header.config.fontVariant = "ULTR";
+ break;
+ case 5: // FONT_VARIANT_QUICKSILVER
+ this.header.config.fontVariant = "QUIC";
+ break;
+ default:
+ this.header.config.fontVariant = ""; // Empty string for unknown variant
+ }
+ }
+
if (this.header.config.charWidth === 31) {
this.header.config.charWidth = 30;
}
diff --git a/src/osd-overlay/worker.ts b/src/osd-overlay/worker.ts
index 8942dc1..5f193c7 100644
--- a/src/osd-overlay/worker.ts
+++ b/src/osd-overlay/worker.ts
@@ -6,7 +6,6 @@ import {
Font,
FontPack,
FontPackFiles,
- TILES_PER_PAGE,
} from "./fonts";
import { OsdReader } from "./osd";
import { SrtReader } from "./srt";
@@ -65,7 +64,7 @@ export class VideoWorker {
this.srtReader = await SrtReader.fromFile(options.srtFile);
}
- this.fontPack = await Font.fromFiles(options.fontFiles);
+ this.fontPack = await Font.fromFiles(options.fontFiles, this.osdReader);
const {
width,
@@ -192,19 +191,13 @@ export class VideoWorker {
let font: Font;
if (this.hd) {
- font =
- osdFrameChar < TILES_PER_PAGE
- ? this.fontPack!.hd1
- : this.fontPack!.hd2;
+ font = this.fontPack!.hd;
} else {
- font =
- osdFrameChar < TILES_PER_PAGE
- ? this.fontPack!.sd1
- : this.fontPack!.sd2;
+ font = this.fontPack!.sd;
}
osdCtx.drawImage(
- font.getTile(osdFrameChar % TILES_PER_PAGE),
+ font.getTile(osdFrameChar),
x * this.osdReader!.header.config.fontWidth,
y * this.osdReader!.header.config.fontHeight
);
diff --git a/src/translations/en/osdOverlay.json b/src/translations/en/osdOverlay.json
index bbdf35f..0dae800 100644
--- a/src/translations/en/osdOverlay.json
+++ b/src/translations/en/osdOverlay.json
@@ -17,6 +17,8 @@
"fileDropFontHd2": "Font 2 (HD)",
"fileDropFontSd1": "Font 1 (SD)",
"fileDropFontSd2": "Font 2 (SD)",
+ "fileDropFontHd": "Custom HD Font (optional)",
+ "fileDropFontSd": "Custom SD Font (optional)",
"fileDropHelp": "You can drop any of your files here, or click to select them individually.",
"fileDropOsd": "OSD",
"fileDropSrt": "SRT (optional)",