@bendyline/squisq-video 2.4.19 → 2.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +29 -2
- package/dist/index.js +39 -4
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -233,7 +233,8 @@ declare function computeAudioTimeline(doc: Doc, coverPreRoll?: number, options?:
|
|
|
233
233
|
* Render HTML Generation for Video Frame Capture
|
|
234
234
|
*
|
|
235
235
|
* Generates a self-contained HTML document that loads the SquisqPlayer standalone
|
|
236
|
-
* bundle in renderMode, embedding all images and audio as base64 data URIs
|
|
236
|
+
* bundle in renderMode, embedding all images and audio as base64 data URIs, and
|
|
237
|
+
* any font files the host supplies (`fonts`) as `@font-face` rules.
|
|
237
238
|
*
|
|
238
239
|
* The generated page mounts one standalone player whose instance handle is
|
|
239
240
|
* available through `SquisqPlayer.getHandle(root)`. Headless callers use that
|
|
@@ -242,6 +243,27 @@ declare function computeAudioTimeline(doc: Doc, coverPreRoll?: number, options?:
|
|
|
242
243
|
* Browser-pure: uses only btoa() and Uint8Array — no Node.js APIs.
|
|
243
244
|
*/
|
|
244
245
|
|
|
246
|
+
/**
|
|
247
|
+
* A font face embedded in the render page. Capture pages load nothing from the
|
|
248
|
+
* network, so a theme font the rendering machine lacks (any Google Fonts stack,
|
|
249
|
+
* such as `dm-sans`) falls back to a system face unless its file is supplied.
|
|
250
|
+
* One entry per file: a family split into unicode-range subsets, or into
|
|
251
|
+
* upright and italic files, takes one entry for each.
|
|
252
|
+
*/
|
|
253
|
+
interface RenderFontFace {
|
|
254
|
+
/** CSS family name as the theme's font stack spells it, e.g. `DM Sans`. */
|
|
255
|
+
family: string;
|
|
256
|
+
/** The font file's bytes (an ArrayBuffer, or a Uint8Array such as a Node Buffer). */
|
|
257
|
+
data: ArrayBuffer | Uint8Array;
|
|
258
|
+
/** File format (default 'woff2'). */
|
|
259
|
+
format?: 'woff2' | 'woff' | 'truetype' | 'opentype';
|
|
260
|
+
/** CSS `font-weight`: one weight, or a variable font's range such as `100 1000` (default `normal`). */
|
|
261
|
+
weight?: number | string;
|
|
262
|
+
/** CSS `font-style` (default 'normal'). */
|
|
263
|
+
style?: 'normal' | 'italic';
|
|
264
|
+
/** CSS `unicode-range`, when the file holds one subset of the family. */
|
|
265
|
+
unicodeRange?: string;
|
|
266
|
+
}
|
|
245
267
|
interface RenderHtmlOptions {
|
|
246
268
|
/** The IIFE player bundle source code (from PLAYER_BUNDLE) */
|
|
247
269
|
playerScript: string;
|
|
@@ -286,6 +308,11 @@ interface RenderHtmlOptions {
|
|
|
286
308
|
* single-frame image capture.
|
|
287
309
|
*/
|
|
288
310
|
displayMode?: 'slideshow' | 'dashboard';
|
|
311
|
+
/**
|
|
312
|
+
* Font files to embed as `@font-face` rules (default none). Faces load
|
|
313
|
+
* before the player mounts, so `document.fonts.ready` covers them.
|
|
314
|
+
*/
|
|
315
|
+
fonts?: readonly RenderFontFace[];
|
|
289
316
|
/** Dashboard-mode options (ignored unless `displayMode` is 'dashboard'). */
|
|
290
317
|
dashboard?: {
|
|
291
318
|
/** Layout id or 'auto'. Overrides doc frontmatter. */
|
|
@@ -531,4 +558,4 @@ declare function frameTimeSeconds(index: number, fps: number): number;
|
|
|
531
558
|
/** Number of frames needed to cover `durationSeconds` at `fps` (partial frames round up). */
|
|
532
559
|
declare function frameCountFor(durationSeconds: number, fps: number): number;
|
|
533
560
|
|
|
534
|
-
export { type AudioTimelineClip, type ComputeAudioTimelineOptions, DASHBOARD_RESOLUTIONS, DEFAULT_DASHBOARD_RESOLUTION, type DashboardResolutionId, type DashboardResolutionPreset, type EncoderResult, FFMPEG_WASM_SETUP_HINT, type FfmpegWasmLoadConfig, type GifDither, type GifFilterOptions, type GifOutputOptions, MAX_DASHBOARD_IMAGE_DIMENSION, MAX_DASHBOARD_IMAGE_PIXELS, MIN_DASHBOARD_IMAGE_DIMENSION, ORIENTATION_DIMENSIONS, QUALITY_PRESETS, type QualityPreset, type RenderHtmlOptions, type ResolveDashboardDimensionsInput, type ResolvedDashboardDimensions, type VideoExportOptions, type VideoOrientation, type VideoQuality, audioBitrateArg, bitrateForQuality, computeAudioTimeline, dashboardFamilyForDimensions, ffmpegAudioMuxArgs, ffmpegGifFilterGraph, ffmpegGifOutputArgs, ffmpegGifPaletteApplicationArgs, ffmpegGifPaletteApplicationGraph, ffmpegGifPaletteGenerationFilter, ffmpegVideoQualityArgs, frameCountFor, frameTimeSeconds, framesToMp4Wasm, generateRenderHtml, resolveDashboardDimensions, resolveDimensions, resolveFfmpegWasmLoad, validateDashboardImageDimensions, validateVideoExportOptions };
|
|
561
|
+
export { type AudioTimelineClip, type ComputeAudioTimelineOptions, DASHBOARD_RESOLUTIONS, DEFAULT_DASHBOARD_RESOLUTION, type DashboardResolutionId, type DashboardResolutionPreset, type EncoderResult, FFMPEG_WASM_SETUP_HINT, type FfmpegWasmLoadConfig, type GifDither, type GifFilterOptions, type GifOutputOptions, MAX_DASHBOARD_IMAGE_DIMENSION, MAX_DASHBOARD_IMAGE_PIXELS, MIN_DASHBOARD_IMAGE_DIMENSION, ORIENTATION_DIMENSIONS, QUALITY_PRESETS, type QualityPreset, type RenderFontFace, type RenderHtmlOptions, type ResolveDashboardDimensionsInput, type ResolvedDashboardDimensions, type VideoExportOptions, type VideoOrientation, type VideoQuality, audioBitrateArg, bitrateForQuality, computeAudioTimeline, dashboardFamilyForDimensions, ffmpegAudioMuxArgs, ffmpegGifFilterGraph, ffmpegGifOutputArgs, ffmpegGifPaletteApplicationArgs, ffmpegGifPaletteApplicationGraph, ffmpegGifPaletteGenerationFilter, ffmpegVideoQualityArgs, frameCountFor, frameTimeSeconds, framesToMp4Wasm, generateRenderHtml, resolveDashboardDimensions, resolveDimensions, resolveFfmpegWasmLoad, validateDashboardImageDimensions, validateVideoExportOptions };
|
package/dist/index.js
CHANGED
|
@@ -174,7 +174,7 @@ function inferMimeType(filename) {
|
|
|
174
174
|
}
|
|
175
175
|
var BINARY_STRING_CHUNK = 32768;
|
|
176
176
|
function arrayBufferToDataUrl(buffer, mimeType) {
|
|
177
|
-
const bytes = new Uint8Array(buffer);
|
|
177
|
+
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
178
178
|
const parts = [];
|
|
179
179
|
for (let i = 0; i < bytes.length; i += BINARY_STRING_CHUNK) {
|
|
180
180
|
parts.push(String.fromCharCode(...bytes.subarray(i, i + BINARY_STRING_CHUNK)));
|
|
@@ -187,6 +187,37 @@ function escapeForScript(str) {
|
|
|
187
187
|
function escapeHtml(str) {
|
|
188
188
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
189
189
|
}
|
|
190
|
+
var FONT_MIME = {
|
|
191
|
+
woff2: "font/woff2",
|
|
192
|
+
woff: "font/woff",
|
|
193
|
+
truetype: "font/ttf",
|
|
194
|
+
opentype: "font/otf"
|
|
195
|
+
};
|
|
196
|
+
var FONT_FAMILY = /^[\p{L}\p{N} _.-]+$/u;
|
|
197
|
+
var FONT_WEIGHT = /^(?:normal|bold|\d{1,4}(?: \d{1,4})?)$/;
|
|
198
|
+
var UNICODE_RANGE = /^U\+[0-9A-F?]{1,6}(?:-[0-9A-F]{1,6})?(?:, ?U\+[0-9A-F?]{1,6}(?:-[0-9A-F]{1,6})?)*$/i;
|
|
199
|
+
function fontFaceCss(fonts) {
|
|
200
|
+
return fonts.map((font) => {
|
|
201
|
+
const family = font.family.trim();
|
|
202
|
+
const format = font.format ?? "woff2";
|
|
203
|
+
const weight = String(font.weight ?? "normal").trim();
|
|
204
|
+
const style = font.style ?? "normal";
|
|
205
|
+
if (!FONT_FAMILY.test(family)) throw new Error(`Invalid font family name: ${font.family}`);
|
|
206
|
+
if (!(format in FONT_MIME)) throw new Error(`Unsupported font format: ${format}`);
|
|
207
|
+
if (!FONT_WEIGHT.test(weight)) {
|
|
208
|
+
throw new Error(`Invalid font weight for ${family}: ${weight}`);
|
|
209
|
+
}
|
|
210
|
+
if (style !== "normal" && style !== "italic") {
|
|
211
|
+
throw new Error(`Invalid font style for ${family}: ${String(style)}`);
|
|
212
|
+
}
|
|
213
|
+
if (font.unicodeRange !== void 0 && !UNICODE_RANGE.test(font.unicodeRange.trim())) {
|
|
214
|
+
throw new Error(`Invalid unicode-range for ${family}: ${font.unicodeRange}`);
|
|
215
|
+
}
|
|
216
|
+
const src = arrayBufferToDataUrl(font.data, FONT_MIME[format]);
|
|
217
|
+
const range = font.unicodeRange ? `;unicode-range:${font.unicodeRange.trim()}` : "";
|
|
218
|
+
return `@font-face{font-family:"${family}";src:url(${src}) format("${format}");font-weight:${weight};font-style:${style};font-display:block${range}}`;
|
|
219
|
+
}).join("\n");
|
|
220
|
+
}
|
|
190
221
|
function generateRenderHtml(doc, options) {
|
|
191
222
|
const {
|
|
192
223
|
playerScript,
|
|
@@ -204,8 +235,12 @@ function generateRenderHtml(doc, options) {
|
|
|
204
235
|
animationsEnabled = true,
|
|
205
236
|
buildsEnabled = true,
|
|
206
237
|
displayMode = "slideshow",
|
|
207
|
-
dashboard
|
|
238
|
+
dashboard,
|
|
239
|
+
fonts = []
|
|
208
240
|
} = options;
|
|
241
|
+
const fontCss = fonts.length > 0 ? `
|
|
242
|
+
${fontFaceCss(fonts)}` : "";
|
|
243
|
+
const fontLoad = fonts.length > 0 ? "\n if (document.fonts) document.fonts.forEach(function (face) { face.load().catch(function () {}); });" : "";
|
|
209
244
|
const imageMap = {};
|
|
210
245
|
if (images) {
|
|
211
246
|
for (const [path, buffer] of images.entries()) {
|
|
@@ -248,7 +283,7 @@ function generateRenderHtml(doc, options) {
|
|
|
248
283
|
<style>
|
|
249
284
|
*,*::before,*::after{box-sizing:border-box}
|
|
250
285
|
html,body{margin:0;padding:0;width:${width}px;height:${height}px;overflow:hidden;background:#000}
|
|
251
|
-
#squisq-root{width:${width}px;height:${height}px;display:flex;align-items:center;justify-content:center}
|
|
286
|
+
#squisq-root{width:${width}px;height:${height}px;display:flex;align-items:center;justify-content:center}${fontCss}
|
|
252
287
|
</style>
|
|
253
288
|
</head>
|
|
254
289
|
<body>
|
|
@@ -259,7 +294,7 @@ html,body{margin:0;padding:0;width:${width}px;height:${height}px;overflow:hidden
|
|
|
259
294
|
var doc = JSON.parse(${JSON.stringify(docJson)});
|
|
260
295
|
var images = JSON.parse(${JSON.stringify(imageMapJson)});
|
|
261
296
|
var audio = ${audioMapJson === "null" ? "null" : "JSON.parse(" + JSON.stringify(audioMapJson) + ")"};
|
|
262
|
-
var root = document.getElementById("squisq-root")
|
|
297
|
+
var root = document.getElementById("squisq-root");${fontLoad}
|
|
263
298
|
SquisqPlayer.mount(root, doc, {
|
|
264
299
|
mode: ${JSON.stringify(displayMode === "dashboard" ? "dashboard" : "slideshow")},
|
|
265
300
|
images: images,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bendyline/squisq-video",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.20",
|
|
4
4
|
"description": "Cross-runtime video and animated-GIF helpers with browser-based ffmpeg.wasm encoding for Squisq documents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bendyline",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"typecheck": "tsc --noEmit"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@bendyline/squisq": "2.13.
|
|
51
|
+
"@bendyline/squisq": "2.13.14",
|
|
52
52
|
"@ffmpeg/ffmpeg": "0.12.15",
|
|
53
53
|
"@ffmpeg/util": "0.12.2"
|
|
54
54
|
},
|