@shotstack/shotstack-canvas 2.0.4 → 2.0.6
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/README.md +13 -13
- package/dist/entry.node.cjs +80 -51
- package/dist/entry.node.d.cts +3 -1
- package/dist/entry.node.d.ts +3 -1
- package/dist/entry.node.js +79 -51
- package/dist/entry.web.d.ts +3 -1
- package/dist/entry.web.js +949 -1873
- package/dist/{hb-V6YBF7AQ.js → hb-HSWG3Q47.js} +2 -2
- package/dist/{hbjs-PXJWBHW7.js → hbjs-VGYWXH44.js} +2 -2
- package/package.json +1 -1
- package/scripts/postinstall.js +58 -58
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
# @shotstack/shotstack-canvas
|
|
2
|
-
|
|
3
|
-
One package → identical text shaping/wrapping/animation on Web & Node.
|
|
4
|
-
- HarfBuzz WASM for shaping and glyph outlines (via `harfbuzzjs`).
|
|
5
|
-
- Device-independent draw-ops.
|
|
6
|
-
- Painters: Canvas2D (web) and node-canvas (node).
|
|
7
|
-
- Deterministic time-driven animations.
|
|
8
|
-
|
|
9
|
-
## Install
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
pnpm add @shotstack/shotstack-canvas
|
|
13
|
-
# or npm i / yarn add
|
|
1
|
+
# @shotstack/shotstack-canvas
|
|
2
|
+
|
|
3
|
+
One package → identical text shaping/wrapping/animation on Web & Node.
|
|
4
|
+
- HarfBuzz WASM for shaping and glyph outlines (via `harfbuzzjs`).
|
|
5
|
+
- Device-independent draw-ops.
|
|
6
|
+
- Painters: Canvas2D (web) and node-canvas (node).
|
|
7
|
+
- Deterministic time-driven animations.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @shotstack/shotstack-canvas
|
|
13
|
+
# or npm i / yarn add
|
package/dist/entry.node.cjs
CHANGED
|
@@ -362,6 +362,7 @@ __export(entry_node_exports, {
|
|
|
362
362
|
RichCaptionRenderer: () => RichCaptionRenderer,
|
|
363
363
|
WordTimingStore: () => WordTimingStore,
|
|
364
364
|
arcToCubicBeziers: () => arcToCubicBeziers,
|
|
365
|
+
breakIntoLines: () => breakIntoLines,
|
|
365
366
|
calculateAnimationStatesForGroup: () => calculateAnimationStatesForGroup,
|
|
366
367
|
commandsToPathString: () => commandsToPathString,
|
|
367
368
|
computeSimplePathBounds: () => computeSimplePathBounds,
|
|
@@ -581,7 +582,7 @@ var richCaptionFontSchema = import_zod.z.object({
|
|
|
581
582
|
});
|
|
582
583
|
var richCaptionActiveSchema = import_zod2.richCaptionActiveSchema.extend({
|
|
583
584
|
font: import_zod.z.object({
|
|
584
|
-
color: import_zod.z.string().regex(HEX6).default("#
|
|
585
|
+
color: import_zod.z.string().regex(HEX6).default("#ffffff"),
|
|
585
586
|
background: import_zod.z.string().regex(HEX6).optional(),
|
|
586
587
|
opacity: import_zod.z.number().min(0).max(1).default(1)
|
|
587
588
|
}).optional(),
|
|
@@ -4328,7 +4329,7 @@ function groupWordsByPause(store, pauseThreshold = 500) {
|
|
|
4328
4329
|
}
|
|
4329
4330
|
return groups;
|
|
4330
4331
|
}
|
|
4331
|
-
function breakIntoLines(wordWidths, maxWidth,
|
|
4332
|
+
function breakIntoLines(wordWidths, maxWidth, spaceWidth) {
|
|
4332
4333
|
const lines = [];
|
|
4333
4334
|
let currentLine = [];
|
|
4334
4335
|
let currentWidth = 0;
|
|
@@ -4341,15 +4342,12 @@ function breakIntoLines(wordWidths, maxWidth, maxLines, spaceWidth) {
|
|
|
4341
4342
|
} else {
|
|
4342
4343
|
if (currentLine.length > 0) {
|
|
4343
4344
|
lines.push(currentLine);
|
|
4344
|
-
if (lines.length >= maxLines) {
|
|
4345
|
-
return lines;
|
|
4346
|
-
}
|
|
4347
4345
|
}
|
|
4348
4346
|
currentLine = [i];
|
|
4349
4347
|
currentWidth = wordWidth;
|
|
4350
4348
|
}
|
|
4351
4349
|
}
|
|
4352
|
-
if (currentLine.length > 0
|
|
4350
|
+
if (currentLine.length > 0) {
|
|
4353
4351
|
lines.push(currentLine);
|
|
4354
4352
|
}
|
|
4355
4353
|
return lines;
|
|
@@ -4382,6 +4380,13 @@ function transformText(text, transform) {
|
|
|
4382
4380
|
return text;
|
|
4383
4381
|
}
|
|
4384
4382
|
}
|
|
4383
|
+
function splitIntoChunks(arr, chunkSize) {
|
|
4384
|
+
const chunks = [];
|
|
4385
|
+
for (let i = 0; i < arr.length; i += chunkSize) {
|
|
4386
|
+
chunks.push(arr.slice(i, i + chunkSize));
|
|
4387
|
+
}
|
|
4388
|
+
return chunks;
|
|
4389
|
+
}
|
|
4385
4390
|
var CaptionLayoutEngine = class {
|
|
4386
4391
|
fontRegistry;
|
|
4387
4392
|
cache;
|
|
@@ -4468,31 +4473,34 @@ var CaptionLayoutEngine = class {
|
|
|
4468
4473
|
const spaceWord = await this.measureWord(" ", measurementConfig);
|
|
4469
4474
|
spaceWidth = spaceWord.width + config.wordSpacing;
|
|
4470
4475
|
}
|
|
4471
|
-
const groups = wordGroups.
|
|
4476
|
+
const groups = wordGroups.flatMap((indices) => {
|
|
4472
4477
|
const groupWidths = indices.map((i) => store.widths[i]);
|
|
4473
|
-
const
|
|
4478
|
+
const allLines = breakIntoLines(
|
|
4474
4479
|
groupWidths,
|
|
4475
4480
|
pixelMaxWidth,
|
|
4476
|
-
config.maxLines,
|
|
4477
4481
|
spaceWidth
|
|
4478
4482
|
);
|
|
4479
|
-
const
|
|
4480
|
-
|
|
4481
|
-
const
|
|
4483
|
+
const lineChunks = splitIntoChunks(allLines, config.maxLines);
|
|
4484
|
+
return lineChunks.map((chunkLines) => {
|
|
4485
|
+
const lines = chunkLines.map((lineWordIndices, lineIndex) => {
|
|
4486
|
+
const actualIndices = lineWordIndices.map((i) => indices[i]);
|
|
4487
|
+
const lineWidth = actualIndices.reduce((sum, idx) => sum + store.widths[idx], 0) + (actualIndices.length - 1) * spaceWidth;
|
|
4488
|
+
return {
|
|
4489
|
+
wordIndices: actualIndices,
|
|
4490
|
+
x: 0,
|
|
4491
|
+
y: lineIndex * config.fontSize * config.lineHeight,
|
|
4492
|
+
width: lineWidth,
|
|
4493
|
+
height: config.fontSize
|
|
4494
|
+
};
|
|
4495
|
+
});
|
|
4496
|
+
const allWordIndices = lines.flatMap((l) => l.wordIndices);
|
|
4482
4497
|
return {
|
|
4483
|
-
wordIndices:
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
height: config.fontSize
|
|
4498
|
+
wordIndices: allWordIndices,
|
|
4499
|
+
startTime: store.startTimes[allWordIndices[0]],
|
|
4500
|
+
endTime: store.endTimes[allWordIndices[allWordIndices.length - 1]],
|
|
4501
|
+
lines
|
|
4488
4502
|
};
|
|
4489
4503
|
});
|
|
4490
|
-
return {
|
|
4491
|
-
wordIndices: lines.flatMap((l) => l.wordIndices),
|
|
4492
|
-
startTime: store.startTimes[indices[0]],
|
|
4493
|
-
endTime: store.endTimes[indices[indices.length - 1]],
|
|
4494
|
-
lines
|
|
4495
|
-
};
|
|
4496
4504
|
});
|
|
4497
4505
|
const calculateGroupY = (group) => {
|
|
4498
4506
|
const totalHeight = group.lines.length * config.fontSize * config.lineHeight;
|
|
@@ -4871,7 +4879,7 @@ function extractFontConfig(asset) {
|
|
|
4871
4879
|
size: font?.size ?? 24,
|
|
4872
4880
|
weight: String(font?.weight ?? "400"),
|
|
4873
4881
|
baseColor: font?.color ?? "#ffffff",
|
|
4874
|
-
activeColor: active?.color ?? "#
|
|
4882
|
+
activeColor: active?.color ?? "#ffffff",
|
|
4875
4883
|
baseOpacity: font?.opacity ?? 1,
|
|
4876
4884
|
activeOpacity: active?.opacity ?? 1,
|
|
4877
4885
|
letterSpacing: asset.style?.letterSpacing ?? 0
|
|
@@ -5607,6 +5615,7 @@ var NodeRawEncoder = class _NodeRawEncoder {
|
|
|
5607
5615
|
preset = "ultrafast",
|
|
5608
5616
|
profile = "high"
|
|
5609
5617
|
} = config;
|
|
5618
|
+
const hasAlpha = config.hasAlpha ?? false;
|
|
5610
5619
|
const args = [
|
|
5611
5620
|
"-y",
|
|
5612
5621
|
"-f",
|
|
@@ -5620,32 +5629,49 @@ var NodeRawEncoder = class _NodeRawEncoder {
|
|
|
5620
5629
|
"-thread_queue_size",
|
|
5621
5630
|
"512",
|
|
5622
5631
|
"-i",
|
|
5623
|
-
"pipe:0"
|
|
5624
|
-
"-c:v",
|
|
5625
|
-
"libx264",
|
|
5626
|
-
"-preset",
|
|
5627
|
-
preset,
|
|
5628
|
-
"-tune",
|
|
5629
|
-
"stillimage",
|
|
5630
|
-
"-crf",
|
|
5631
|
-
String(crf),
|
|
5632
|
-
"-profile:v",
|
|
5633
|
-
profile,
|
|
5634
|
-
"-g",
|
|
5635
|
-
"300",
|
|
5636
|
-
"-bf",
|
|
5637
|
-
"2",
|
|
5638
|
-
"-threads",
|
|
5639
|
-
"0",
|
|
5640
|
-
"-pix_fmt",
|
|
5641
|
-
"yuv420p",
|
|
5642
|
-
"-r",
|
|
5643
|
-
String(fps),
|
|
5644
|
-
"-movflags",
|
|
5645
|
-
"+faststart"
|
|
5632
|
+
"pipe:0"
|
|
5646
5633
|
];
|
|
5634
|
+
if (hasAlpha) {
|
|
5635
|
+
args.push(
|
|
5636
|
+
"-c:v",
|
|
5637
|
+
"prores_ks",
|
|
5638
|
+
"-profile:v",
|
|
5639
|
+
"4444",
|
|
5640
|
+
"-pix_fmt",
|
|
5641
|
+
"yuva444p10le",
|
|
5642
|
+
"-vendor",
|
|
5643
|
+
"apl0",
|
|
5644
|
+
"-r",
|
|
5645
|
+
String(fps)
|
|
5646
|
+
);
|
|
5647
|
+
} else {
|
|
5648
|
+
args.push(
|
|
5649
|
+
"-c:v",
|
|
5650
|
+
"libx264",
|
|
5651
|
+
"-preset",
|
|
5652
|
+
preset,
|
|
5653
|
+
"-tune",
|
|
5654
|
+
"stillimage",
|
|
5655
|
+
"-crf",
|
|
5656
|
+
String(crf),
|
|
5657
|
+
"-profile:v",
|
|
5658
|
+
profile,
|
|
5659
|
+
"-g",
|
|
5660
|
+
"300",
|
|
5661
|
+
"-bf",
|
|
5662
|
+
"2",
|
|
5663
|
+
"-threads",
|
|
5664
|
+
"0",
|
|
5665
|
+
"-pix_fmt",
|
|
5666
|
+
"yuv420p",
|
|
5667
|
+
"-r",
|
|
5668
|
+
String(fps),
|
|
5669
|
+
"-movflags",
|
|
5670
|
+
"+faststart"
|
|
5671
|
+
);
|
|
5672
|
+
}
|
|
5647
5673
|
if (this.outputToMemory) {
|
|
5648
|
-
args.push("-f", "mp4", "pipe:1");
|
|
5674
|
+
args.push("-f", hasAlpha ? "mov" : "mp4", "pipe:1");
|
|
5649
5675
|
} else {
|
|
5650
5676
|
args.push(this.outputPath);
|
|
5651
5677
|
}
|
|
@@ -5905,6 +5931,8 @@ var RichCaptionRenderer = class {
|
|
|
5905
5931
|
animationStyle,
|
|
5906
5932
|
animationSpeed
|
|
5907
5933
|
);
|
|
5934
|
+
const bgColor = options?.bgColor;
|
|
5935
|
+
const hasAlpha = !bgColor;
|
|
5908
5936
|
const encoder = new NodeRawEncoder();
|
|
5909
5937
|
await encoder.configure(
|
|
5910
5938
|
{
|
|
@@ -5914,7 +5942,8 @@ var RichCaptionRenderer = class {
|
|
|
5914
5942
|
duration,
|
|
5915
5943
|
crf: options?.crf ?? 23,
|
|
5916
5944
|
preset: options?.preset ?? "ultrafast",
|
|
5917
|
-
profile: options?.profile ?? "high"
|
|
5945
|
+
profile: options?.profile ?? "high",
|
|
5946
|
+
hasAlpha
|
|
5918
5947
|
},
|
|
5919
5948
|
{
|
|
5920
5949
|
outputPath,
|
|
@@ -5926,7 +5955,6 @@ var RichCaptionRenderer = class {
|
|
|
5926
5955
|
height: this.height,
|
|
5927
5956
|
pixelRatio: this.pixelRatio
|
|
5928
5957
|
});
|
|
5929
|
-
const bgColor = options?.bgColor ?? "#000000";
|
|
5930
5958
|
const totalStart = performance.now();
|
|
5931
5959
|
let framesProcessed = 0;
|
|
5932
5960
|
let lastPct = -1;
|
|
@@ -5940,7 +5968,7 @@ var RichCaptionRenderer = class {
|
|
|
5940
5968
|
height: this.height * this.pixelRatio,
|
|
5941
5969
|
pixelRatio: this.pixelRatio,
|
|
5942
5970
|
clear: true,
|
|
5943
|
-
bg: { color: bgColor, opacity: 1, radius: 0 }
|
|
5971
|
+
...bgColor ? { bg: { color: bgColor, opacity: 1, radius: 0 } } : {}
|
|
5944
5972
|
};
|
|
5945
5973
|
await painter.render([beginOp, ...captionOps]);
|
|
5946
5974
|
const rawResult = painter.toRawRGBA();
|
|
@@ -6569,6 +6597,7 @@ async function createTextEngine(opts = {}) {
|
|
|
6569
6597
|
RichCaptionRenderer,
|
|
6570
6598
|
WordTimingStore,
|
|
6571
6599
|
arcToCubicBeziers,
|
|
6600
|
+
breakIntoLines,
|
|
6572
6601
|
calculateAnimationStatesForGroup,
|
|
6573
6602
|
commandsToPathString,
|
|
6574
6603
|
computeSimplePathBounds,
|
package/dist/entry.node.d.cts
CHANGED
|
@@ -670,6 +670,7 @@ declare class WordTimingStore {
|
|
|
670
670
|
}
|
|
671
671
|
declare function findWordAtTime(store: WordTimingStore, timeMs: number): number;
|
|
672
672
|
declare function groupWordsByPause(store: WordTimingStore, pauseThreshold?: number): number[][];
|
|
673
|
+
declare function breakIntoLines(wordWidths: number[], maxWidth: number, spaceWidth: number): number[][];
|
|
673
674
|
declare class CaptionLayoutEngine {
|
|
674
675
|
private fontRegistry;
|
|
675
676
|
private cache;
|
|
@@ -1206,6 +1207,7 @@ interface VideoEncoderConfig {
|
|
|
1206
1207
|
hardwareAcceleration?: "prefer-hardware" | "prefer-software" | "no-preference";
|
|
1207
1208
|
crf?: number;
|
|
1208
1209
|
preset?: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow";
|
|
1210
|
+
hasAlpha?: boolean;
|
|
1209
1211
|
}
|
|
1210
1212
|
interface VideoEncoderProgress {
|
|
1211
1213
|
framesEncoded: number;
|
|
@@ -1314,4 +1316,4 @@ declare function createTextEngine(opts?: {
|
|
|
1314
1316
|
destroy(): void;
|
|
1315
1317
|
}>;
|
|
1316
1318
|
|
|
1317
|
-
export { type AnimationDirection, type AnimationStyle, type ArcCommand, type BackgroundConfig, type BoundingBox, type CanvasRichCaptionAsset, CanvasRichCaptionAssetSchema, type CanvasRichTextAsset, CanvasRichTextAssetSchema, type CanvasSvgAsset, CanvasSvgAssetSchema, type CaptionGroup, type CaptionLayout, type CaptionLayoutConfig, CaptionLayoutEngine, type CaptionLine, type ClosePathCommand, type CubicBezierCommand, type DrawOp, type EngineInit, type FastVideoOptions, type FastVideoResult, type FontConfig, FontRegistry, type FrameSchedule, type Glyph, type GradientSpec, type IVideoEncoder, type LineToCommand, type MoveToCommand, NodeRawEncoder, type NormalizedPathCommand, type ParsedPathCommand, type PathCommandType, type Point2D, type PositionedWord, type QuadraticBezierCommand, type RGBA, type RenderFrame, type RenderStats, type Renderer, type ResvgRenderOptions, type ResvgRenderResult, type RichCaptionGeneratorConfig, RichCaptionRenderer, type RichCaptionRendererOptions, type ShadowConfig, type ShapedLine, type ShapedWord, type ShapedWordGlyph, type ShotstackRichTextAsset, type ShotstackSvgAsset, type StrokeConfig, type StrokeSpec, type ValidAsset, type VideoEncoderCapabilities, type VideoEncoderConfig, type VideoEncoderProgress, type WordAnimationConfig, type WordAnimationState, type WordTiming, WordTimingStore, arcToCubicBeziers, calculateAnimationStatesForGroup, commandsToPathString, computeSimplePathBounds, createDefaultGeneratorConfig, createFrameSchedule, createNodePainter, createNodeRawEncoder, createRichCaptionRenderer, createTextEngine, createVideoEncoder, detectPlatform, detectSubtitleFormat, findWordAtTime, generateRichCaptionDrawOps, generateRichCaptionFrame, generateShapePathData, getDefaultAnimationConfig, getDrawCaptionWordOps, getEncoderCapabilities, getEncoderWarning, groupWordsByPause, isDrawCaptionWordOp, isRTLText, isWebCodecsH264Supported, normalizePath, normalizePathString, parseSubtitleToWords, parseSvgPath, quadraticToCubic, renderSvgAssetToPng, renderSvgToPng, richCaptionAssetSchema, shapeToSvgString };
|
|
1319
|
+
export { type AnimationDirection, type AnimationStyle, type ArcCommand, type BackgroundConfig, type BoundingBox, type CanvasRichCaptionAsset, CanvasRichCaptionAssetSchema, type CanvasRichTextAsset, CanvasRichTextAssetSchema, type CanvasSvgAsset, CanvasSvgAssetSchema, type CaptionGroup, type CaptionLayout, type CaptionLayoutConfig, CaptionLayoutEngine, type CaptionLine, type ClosePathCommand, type CubicBezierCommand, type DrawOp, type EngineInit, type FastVideoOptions, type FastVideoResult, type FontConfig, FontRegistry, type FrameSchedule, type Glyph, type GradientSpec, type IVideoEncoder, type LineToCommand, type MoveToCommand, NodeRawEncoder, type NormalizedPathCommand, type ParsedPathCommand, type PathCommandType, type Point2D, type PositionedWord, type QuadraticBezierCommand, type RGBA, type RenderFrame, type RenderStats, type Renderer, type ResvgRenderOptions, type ResvgRenderResult, type RichCaptionGeneratorConfig, RichCaptionRenderer, type RichCaptionRendererOptions, type ShadowConfig, type ShapedLine, type ShapedWord, type ShapedWordGlyph, type ShotstackRichTextAsset, type ShotstackSvgAsset, type StrokeConfig, type StrokeSpec, type ValidAsset, type VideoEncoderCapabilities, type VideoEncoderConfig, type VideoEncoderProgress, type WordAnimationConfig, type WordAnimationState, type WordTiming, WordTimingStore, arcToCubicBeziers, breakIntoLines, calculateAnimationStatesForGroup, commandsToPathString, computeSimplePathBounds, createDefaultGeneratorConfig, createFrameSchedule, createNodePainter, createNodeRawEncoder, createRichCaptionRenderer, createTextEngine, createVideoEncoder, detectPlatform, detectSubtitleFormat, findWordAtTime, generateRichCaptionDrawOps, generateRichCaptionFrame, generateShapePathData, getDefaultAnimationConfig, getDrawCaptionWordOps, getEncoderCapabilities, getEncoderWarning, groupWordsByPause, isDrawCaptionWordOp, isRTLText, isWebCodecsH264Supported, normalizePath, normalizePathString, parseSubtitleToWords, parseSvgPath, quadraticToCubic, renderSvgAssetToPng, renderSvgToPng, richCaptionAssetSchema, shapeToSvgString };
|
package/dist/entry.node.d.ts
CHANGED
|
@@ -670,6 +670,7 @@ declare class WordTimingStore {
|
|
|
670
670
|
}
|
|
671
671
|
declare function findWordAtTime(store: WordTimingStore, timeMs: number): number;
|
|
672
672
|
declare function groupWordsByPause(store: WordTimingStore, pauseThreshold?: number): number[][];
|
|
673
|
+
declare function breakIntoLines(wordWidths: number[], maxWidth: number, spaceWidth: number): number[][];
|
|
673
674
|
declare class CaptionLayoutEngine {
|
|
674
675
|
private fontRegistry;
|
|
675
676
|
private cache;
|
|
@@ -1206,6 +1207,7 @@ interface VideoEncoderConfig {
|
|
|
1206
1207
|
hardwareAcceleration?: "prefer-hardware" | "prefer-software" | "no-preference";
|
|
1207
1208
|
crf?: number;
|
|
1208
1209
|
preset?: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow";
|
|
1210
|
+
hasAlpha?: boolean;
|
|
1209
1211
|
}
|
|
1210
1212
|
interface VideoEncoderProgress {
|
|
1211
1213
|
framesEncoded: number;
|
|
@@ -1314,4 +1316,4 @@ declare function createTextEngine(opts?: {
|
|
|
1314
1316
|
destroy(): void;
|
|
1315
1317
|
}>;
|
|
1316
1318
|
|
|
1317
|
-
export { type AnimationDirection, type AnimationStyle, type ArcCommand, type BackgroundConfig, type BoundingBox, type CanvasRichCaptionAsset, CanvasRichCaptionAssetSchema, type CanvasRichTextAsset, CanvasRichTextAssetSchema, type CanvasSvgAsset, CanvasSvgAssetSchema, type CaptionGroup, type CaptionLayout, type CaptionLayoutConfig, CaptionLayoutEngine, type CaptionLine, type ClosePathCommand, type CubicBezierCommand, type DrawOp, type EngineInit, type FastVideoOptions, type FastVideoResult, type FontConfig, FontRegistry, type FrameSchedule, type Glyph, type GradientSpec, type IVideoEncoder, type LineToCommand, type MoveToCommand, NodeRawEncoder, type NormalizedPathCommand, type ParsedPathCommand, type PathCommandType, type Point2D, type PositionedWord, type QuadraticBezierCommand, type RGBA, type RenderFrame, type RenderStats, type Renderer, type ResvgRenderOptions, type ResvgRenderResult, type RichCaptionGeneratorConfig, RichCaptionRenderer, type RichCaptionRendererOptions, type ShadowConfig, type ShapedLine, type ShapedWord, type ShapedWordGlyph, type ShotstackRichTextAsset, type ShotstackSvgAsset, type StrokeConfig, type StrokeSpec, type ValidAsset, type VideoEncoderCapabilities, type VideoEncoderConfig, type VideoEncoderProgress, type WordAnimationConfig, type WordAnimationState, type WordTiming, WordTimingStore, arcToCubicBeziers, calculateAnimationStatesForGroup, commandsToPathString, computeSimplePathBounds, createDefaultGeneratorConfig, createFrameSchedule, createNodePainter, createNodeRawEncoder, createRichCaptionRenderer, createTextEngine, createVideoEncoder, detectPlatform, detectSubtitleFormat, findWordAtTime, generateRichCaptionDrawOps, generateRichCaptionFrame, generateShapePathData, getDefaultAnimationConfig, getDrawCaptionWordOps, getEncoderCapabilities, getEncoderWarning, groupWordsByPause, isDrawCaptionWordOp, isRTLText, isWebCodecsH264Supported, normalizePath, normalizePathString, parseSubtitleToWords, parseSvgPath, quadraticToCubic, renderSvgAssetToPng, renderSvgToPng, richCaptionAssetSchema, shapeToSvgString };
|
|
1319
|
+
export { type AnimationDirection, type AnimationStyle, type ArcCommand, type BackgroundConfig, type BoundingBox, type CanvasRichCaptionAsset, CanvasRichCaptionAssetSchema, type CanvasRichTextAsset, CanvasRichTextAssetSchema, type CanvasSvgAsset, CanvasSvgAssetSchema, type CaptionGroup, type CaptionLayout, type CaptionLayoutConfig, CaptionLayoutEngine, type CaptionLine, type ClosePathCommand, type CubicBezierCommand, type DrawOp, type EngineInit, type FastVideoOptions, type FastVideoResult, type FontConfig, FontRegistry, type FrameSchedule, type Glyph, type GradientSpec, type IVideoEncoder, type LineToCommand, type MoveToCommand, NodeRawEncoder, type NormalizedPathCommand, type ParsedPathCommand, type PathCommandType, type Point2D, type PositionedWord, type QuadraticBezierCommand, type RGBA, type RenderFrame, type RenderStats, type Renderer, type ResvgRenderOptions, type ResvgRenderResult, type RichCaptionGeneratorConfig, RichCaptionRenderer, type RichCaptionRendererOptions, type ShadowConfig, type ShapedLine, type ShapedWord, type ShapedWordGlyph, type ShotstackRichTextAsset, type ShotstackSvgAsset, type StrokeConfig, type StrokeSpec, type ValidAsset, type VideoEncoderCapabilities, type VideoEncoderConfig, type VideoEncoderProgress, type WordAnimationConfig, type WordAnimationState, type WordTiming, WordTimingStore, arcToCubicBeziers, breakIntoLines, calculateAnimationStatesForGroup, commandsToPathString, computeSimplePathBounds, createDefaultGeneratorConfig, createFrameSchedule, createNodePainter, createNodeRawEncoder, createRichCaptionRenderer, createTextEngine, createVideoEncoder, detectPlatform, detectSubtitleFormat, findWordAtTime, generateRichCaptionDrawOps, generateRichCaptionFrame, generateShapePathData, getDefaultAnimationConfig, getDrawCaptionWordOps, getEncoderCapabilities, getEncoderWarning, groupWordsByPause, isDrawCaptionWordOp, isRTLText, isWebCodecsH264Supported, normalizePath, normalizePathString, parseSubtitleToWords, parseSvgPath, quadraticToCubic, renderSvgAssetToPng, renderSvgToPng, richCaptionAssetSchema, shapeToSvgString };
|
package/dist/entry.node.js
CHANGED
|
@@ -193,7 +193,7 @@ var richCaptionFontSchema = z.object({
|
|
|
193
193
|
});
|
|
194
194
|
var richCaptionActiveSchema = baseCaptionActiveSchema.extend({
|
|
195
195
|
font: z.object({
|
|
196
|
-
color: z.string().regex(HEX6).default("#
|
|
196
|
+
color: z.string().regex(HEX6).default("#ffffff"),
|
|
197
197
|
background: z.string().regex(HEX6).optional(),
|
|
198
198
|
opacity: z.number().min(0).max(1).default(1)
|
|
199
199
|
}).optional(),
|
|
@@ -3939,7 +3939,7 @@ function groupWordsByPause(store, pauseThreshold = 500) {
|
|
|
3939
3939
|
}
|
|
3940
3940
|
return groups;
|
|
3941
3941
|
}
|
|
3942
|
-
function breakIntoLines(wordWidths, maxWidth,
|
|
3942
|
+
function breakIntoLines(wordWidths, maxWidth, spaceWidth) {
|
|
3943
3943
|
const lines = [];
|
|
3944
3944
|
let currentLine = [];
|
|
3945
3945
|
let currentWidth = 0;
|
|
@@ -3952,15 +3952,12 @@ function breakIntoLines(wordWidths, maxWidth, maxLines, spaceWidth) {
|
|
|
3952
3952
|
} else {
|
|
3953
3953
|
if (currentLine.length > 0) {
|
|
3954
3954
|
lines.push(currentLine);
|
|
3955
|
-
if (lines.length >= maxLines) {
|
|
3956
|
-
return lines;
|
|
3957
|
-
}
|
|
3958
3955
|
}
|
|
3959
3956
|
currentLine = [i];
|
|
3960
3957
|
currentWidth = wordWidth;
|
|
3961
3958
|
}
|
|
3962
3959
|
}
|
|
3963
|
-
if (currentLine.length > 0
|
|
3960
|
+
if (currentLine.length > 0) {
|
|
3964
3961
|
lines.push(currentLine);
|
|
3965
3962
|
}
|
|
3966
3963
|
return lines;
|
|
@@ -3993,6 +3990,13 @@ function transformText(text, transform) {
|
|
|
3993
3990
|
return text;
|
|
3994
3991
|
}
|
|
3995
3992
|
}
|
|
3993
|
+
function splitIntoChunks(arr, chunkSize) {
|
|
3994
|
+
const chunks = [];
|
|
3995
|
+
for (let i = 0; i < arr.length; i += chunkSize) {
|
|
3996
|
+
chunks.push(arr.slice(i, i + chunkSize));
|
|
3997
|
+
}
|
|
3998
|
+
return chunks;
|
|
3999
|
+
}
|
|
3996
4000
|
var CaptionLayoutEngine = class {
|
|
3997
4001
|
fontRegistry;
|
|
3998
4002
|
cache;
|
|
@@ -4079,31 +4083,34 @@ var CaptionLayoutEngine = class {
|
|
|
4079
4083
|
const spaceWord = await this.measureWord(" ", measurementConfig);
|
|
4080
4084
|
spaceWidth = spaceWord.width + config.wordSpacing;
|
|
4081
4085
|
}
|
|
4082
|
-
const groups = wordGroups.
|
|
4086
|
+
const groups = wordGroups.flatMap((indices) => {
|
|
4083
4087
|
const groupWidths = indices.map((i) => store.widths[i]);
|
|
4084
|
-
const
|
|
4088
|
+
const allLines = breakIntoLines(
|
|
4085
4089
|
groupWidths,
|
|
4086
4090
|
pixelMaxWidth,
|
|
4087
|
-
config.maxLines,
|
|
4088
4091
|
spaceWidth
|
|
4089
4092
|
);
|
|
4090
|
-
const
|
|
4091
|
-
|
|
4092
|
-
const
|
|
4093
|
+
const lineChunks = splitIntoChunks(allLines, config.maxLines);
|
|
4094
|
+
return lineChunks.map((chunkLines) => {
|
|
4095
|
+
const lines = chunkLines.map((lineWordIndices, lineIndex) => {
|
|
4096
|
+
const actualIndices = lineWordIndices.map((i) => indices[i]);
|
|
4097
|
+
const lineWidth = actualIndices.reduce((sum, idx) => sum + store.widths[idx], 0) + (actualIndices.length - 1) * spaceWidth;
|
|
4098
|
+
return {
|
|
4099
|
+
wordIndices: actualIndices,
|
|
4100
|
+
x: 0,
|
|
4101
|
+
y: lineIndex * config.fontSize * config.lineHeight,
|
|
4102
|
+
width: lineWidth,
|
|
4103
|
+
height: config.fontSize
|
|
4104
|
+
};
|
|
4105
|
+
});
|
|
4106
|
+
const allWordIndices = lines.flatMap((l) => l.wordIndices);
|
|
4093
4107
|
return {
|
|
4094
|
-
wordIndices:
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
height: config.fontSize
|
|
4108
|
+
wordIndices: allWordIndices,
|
|
4109
|
+
startTime: store.startTimes[allWordIndices[0]],
|
|
4110
|
+
endTime: store.endTimes[allWordIndices[allWordIndices.length - 1]],
|
|
4111
|
+
lines
|
|
4099
4112
|
};
|
|
4100
4113
|
});
|
|
4101
|
-
return {
|
|
4102
|
-
wordIndices: lines.flatMap((l) => l.wordIndices),
|
|
4103
|
-
startTime: store.startTimes[indices[0]],
|
|
4104
|
-
endTime: store.endTimes[indices[indices.length - 1]],
|
|
4105
|
-
lines
|
|
4106
|
-
};
|
|
4107
4114
|
});
|
|
4108
4115
|
const calculateGroupY = (group) => {
|
|
4109
4116
|
const totalHeight = group.lines.length * config.fontSize * config.lineHeight;
|
|
@@ -4482,7 +4489,7 @@ function extractFontConfig(asset) {
|
|
|
4482
4489
|
size: font?.size ?? 24,
|
|
4483
4490
|
weight: String(font?.weight ?? "400"),
|
|
4484
4491
|
baseColor: font?.color ?? "#ffffff",
|
|
4485
|
-
activeColor: active?.color ?? "#
|
|
4492
|
+
activeColor: active?.color ?? "#ffffff",
|
|
4486
4493
|
baseOpacity: font?.opacity ?? 1,
|
|
4487
4494
|
activeOpacity: active?.opacity ?? 1,
|
|
4488
4495
|
letterSpacing: asset.style?.letterSpacing ?? 0
|
|
@@ -5218,6 +5225,7 @@ var NodeRawEncoder = class _NodeRawEncoder {
|
|
|
5218
5225
|
preset = "ultrafast",
|
|
5219
5226
|
profile = "high"
|
|
5220
5227
|
} = config;
|
|
5228
|
+
const hasAlpha = config.hasAlpha ?? false;
|
|
5221
5229
|
const args = [
|
|
5222
5230
|
"-y",
|
|
5223
5231
|
"-f",
|
|
@@ -5231,32 +5239,49 @@ var NodeRawEncoder = class _NodeRawEncoder {
|
|
|
5231
5239
|
"-thread_queue_size",
|
|
5232
5240
|
"512",
|
|
5233
5241
|
"-i",
|
|
5234
|
-
"pipe:0"
|
|
5235
|
-
"-c:v",
|
|
5236
|
-
"libx264",
|
|
5237
|
-
"-preset",
|
|
5238
|
-
preset,
|
|
5239
|
-
"-tune",
|
|
5240
|
-
"stillimage",
|
|
5241
|
-
"-crf",
|
|
5242
|
-
String(crf),
|
|
5243
|
-
"-profile:v",
|
|
5244
|
-
profile,
|
|
5245
|
-
"-g",
|
|
5246
|
-
"300",
|
|
5247
|
-
"-bf",
|
|
5248
|
-
"2",
|
|
5249
|
-
"-threads",
|
|
5250
|
-
"0",
|
|
5251
|
-
"-pix_fmt",
|
|
5252
|
-
"yuv420p",
|
|
5253
|
-
"-r",
|
|
5254
|
-
String(fps),
|
|
5255
|
-
"-movflags",
|
|
5256
|
-
"+faststart"
|
|
5242
|
+
"pipe:0"
|
|
5257
5243
|
];
|
|
5244
|
+
if (hasAlpha) {
|
|
5245
|
+
args.push(
|
|
5246
|
+
"-c:v",
|
|
5247
|
+
"prores_ks",
|
|
5248
|
+
"-profile:v",
|
|
5249
|
+
"4444",
|
|
5250
|
+
"-pix_fmt",
|
|
5251
|
+
"yuva444p10le",
|
|
5252
|
+
"-vendor",
|
|
5253
|
+
"apl0",
|
|
5254
|
+
"-r",
|
|
5255
|
+
String(fps)
|
|
5256
|
+
);
|
|
5257
|
+
} else {
|
|
5258
|
+
args.push(
|
|
5259
|
+
"-c:v",
|
|
5260
|
+
"libx264",
|
|
5261
|
+
"-preset",
|
|
5262
|
+
preset,
|
|
5263
|
+
"-tune",
|
|
5264
|
+
"stillimage",
|
|
5265
|
+
"-crf",
|
|
5266
|
+
String(crf),
|
|
5267
|
+
"-profile:v",
|
|
5268
|
+
profile,
|
|
5269
|
+
"-g",
|
|
5270
|
+
"300",
|
|
5271
|
+
"-bf",
|
|
5272
|
+
"2",
|
|
5273
|
+
"-threads",
|
|
5274
|
+
"0",
|
|
5275
|
+
"-pix_fmt",
|
|
5276
|
+
"yuv420p",
|
|
5277
|
+
"-r",
|
|
5278
|
+
String(fps),
|
|
5279
|
+
"-movflags",
|
|
5280
|
+
"+faststart"
|
|
5281
|
+
);
|
|
5282
|
+
}
|
|
5258
5283
|
if (this.outputToMemory) {
|
|
5259
|
-
args.push("-f", "mp4", "pipe:1");
|
|
5284
|
+
args.push("-f", hasAlpha ? "mov" : "mp4", "pipe:1");
|
|
5260
5285
|
} else {
|
|
5261
5286
|
args.push(this.outputPath);
|
|
5262
5287
|
}
|
|
@@ -5516,6 +5541,8 @@ var RichCaptionRenderer = class {
|
|
|
5516
5541
|
animationStyle,
|
|
5517
5542
|
animationSpeed
|
|
5518
5543
|
);
|
|
5544
|
+
const bgColor = options?.bgColor;
|
|
5545
|
+
const hasAlpha = !bgColor;
|
|
5519
5546
|
const encoder = new NodeRawEncoder();
|
|
5520
5547
|
await encoder.configure(
|
|
5521
5548
|
{
|
|
@@ -5525,7 +5552,8 @@ var RichCaptionRenderer = class {
|
|
|
5525
5552
|
duration,
|
|
5526
5553
|
crf: options?.crf ?? 23,
|
|
5527
5554
|
preset: options?.preset ?? "ultrafast",
|
|
5528
|
-
profile: options?.profile ?? "high"
|
|
5555
|
+
profile: options?.profile ?? "high",
|
|
5556
|
+
hasAlpha
|
|
5529
5557
|
},
|
|
5530
5558
|
{
|
|
5531
5559
|
outputPath,
|
|
@@ -5537,7 +5565,6 @@ var RichCaptionRenderer = class {
|
|
|
5537
5565
|
height: this.height,
|
|
5538
5566
|
pixelRatio: this.pixelRatio
|
|
5539
5567
|
});
|
|
5540
|
-
const bgColor = options?.bgColor ?? "#000000";
|
|
5541
5568
|
const totalStart = performance.now();
|
|
5542
5569
|
let framesProcessed = 0;
|
|
5543
5570
|
let lastPct = -1;
|
|
@@ -5551,7 +5578,7 @@ var RichCaptionRenderer = class {
|
|
|
5551
5578
|
height: this.height * this.pixelRatio,
|
|
5552
5579
|
pixelRatio: this.pixelRatio,
|
|
5553
5580
|
clear: true,
|
|
5554
|
-
bg: { color: bgColor, opacity: 1, radius: 0 }
|
|
5581
|
+
...bgColor ? { bg: { color: bgColor, opacity: 1, radius: 0 } } : {}
|
|
5555
5582
|
};
|
|
5556
5583
|
await painter.render([beginOp, ...captionOps]);
|
|
5557
5584
|
const rawResult = painter.toRawRGBA();
|
|
@@ -6179,6 +6206,7 @@ export {
|
|
|
6179
6206
|
RichCaptionRenderer,
|
|
6180
6207
|
WordTimingStore,
|
|
6181
6208
|
arcToCubicBeziers,
|
|
6209
|
+
breakIntoLines,
|
|
6182
6210
|
calculateAnimationStatesForGroup,
|
|
6183
6211
|
commandsToPathString,
|
|
6184
6212
|
computeSimplePathBounds,
|
package/dist/entry.web.d.ts
CHANGED
|
@@ -670,6 +670,7 @@ declare class WordTimingStore {
|
|
|
670
670
|
}
|
|
671
671
|
declare function findWordAtTime(store: WordTimingStore, timeMs: number): number;
|
|
672
672
|
declare function groupWordsByPause(store: WordTimingStore, pauseThreshold?: number): number[][];
|
|
673
|
+
declare function breakIntoLines(wordWidths: number[], maxWidth: number, spaceWidth: number): number[][];
|
|
673
674
|
declare class CaptionLayoutEngine {
|
|
674
675
|
private fontRegistry;
|
|
675
676
|
private cache;
|
|
@@ -1147,6 +1148,7 @@ interface VideoEncoderConfig {
|
|
|
1147
1148
|
hardwareAcceleration?: "prefer-hardware" | "prefer-software" | "no-preference";
|
|
1148
1149
|
crf?: number;
|
|
1149
1150
|
preset?: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow";
|
|
1151
|
+
hasAlpha?: boolean;
|
|
1150
1152
|
}
|
|
1151
1153
|
interface VideoEncoderProgress {
|
|
1152
1154
|
framesEncoded: number;
|
|
@@ -1259,4 +1261,4 @@ declare function createTextEngine(opts?: {
|
|
|
1259
1261
|
destroy(): void;
|
|
1260
1262
|
}>;
|
|
1261
1263
|
|
|
1262
|
-
export { type AnimationDirection, type AnimationStyle, type ArcCommand, type BackgroundConfig, type BoundingBox, type CanvasRichCaptionAsset, CanvasRichCaptionAssetSchema, type CanvasRichTextAsset, CanvasRichTextAssetSchema, type CanvasSvgAsset, CanvasSvgAssetSchema, type CaptionGroup, type CaptionLayout, type CaptionLayoutConfig, CaptionLayoutEngine, type CaptionLine, type ClosePathCommand, type CubicBezierCommand, type DrawOp, type EngineInit, type FastVideoOptions, type FastVideoResult, type FontConfig, FontRegistry, type FrameSchedule, type Glyph, type GradientSpec, type IVideoEncoder, type LineToCommand, MediaRecorderFallback, type MoveToCommand, type NormalizedPathCommand, type ParsedPathCommand, type PathCommandType, type Point2D, type PositionedWord, type QuadraticBezierCommand, type RGBA, type RenderFrame, type RenderStats, type Renderer, type ResvgRenderOptions, type ResvgRenderResult, type RichCaptionGeneratorConfig, type RichCaptionRendererOptions, type ShadowConfig, type ShapedLine, type ShapedWord, type ShapedWordGlyph, type ShotstackRichTextAsset, type ShotstackSvgAsset, type StrokeConfig, type StrokeSpec, type ValidAsset, type VideoEncoderCapabilities, type VideoEncoderConfig, type VideoEncoderProgress, WebCodecsEncoder, type WordAnimationConfig, type WordAnimationState, type WordTiming, WordTimingStore, arcToCubicBeziers, calculateAnimationStatesForGroup, commandsToPathString, computeSimplePathBounds, createDefaultGeneratorConfig, createFrameSchedule, createMediaRecorderFallback, createTextEngine, createVideoEncoder, createWebCodecsEncoder, createWebPainter, detectPlatform, detectSubtitleFormat, findWordAtTime, generateRichCaptionDrawOps, generateRichCaptionFrame, generateShapePathData, getDefaultAnimationConfig, getDrawCaptionWordOps, getEncoderCapabilities, getEncoderWarning, groupWordsByPause, initResvg, isDrawCaptionWordOp, isMediaRecorderSupported, isRTLText, isWebCodecsH264Supported, normalizePath, normalizePathString, parseSubtitleToWords, parseSvgPath, quadraticToCubic, renderSvgAssetToPng, renderSvgToPng, richCaptionAssetSchema, shapeToSvgString };
|
|
1264
|
+
export { type AnimationDirection, type AnimationStyle, type ArcCommand, type BackgroundConfig, type BoundingBox, type CanvasRichCaptionAsset, CanvasRichCaptionAssetSchema, type CanvasRichTextAsset, CanvasRichTextAssetSchema, type CanvasSvgAsset, CanvasSvgAssetSchema, type CaptionGroup, type CaptionLayout, type CaptionLayoutConfig, CaptionLayoutEngine, type CaptionLine, type ClosePathCommand, type CubicBezierCommand, type DrawOp, type EngineInit, type FastVideoOptions, type FastVideoResult, type FontConfig, FontRegistry, type FrameSchedule, type Glyph, type GradientSpec, type IVideoEncoder, type LineToCommand, MediaRecorderFallback, type MoveToCommand, type NormalizedPathCommand, type ParsedPathCommand, type PathCommandType, type Point2D, type PositionedWord, type QuadraticBezierCommand, type RGBA, type RenderFrame, type RenderStats, type Renderer, type ResvgRenderOptions, type ResvgRenderResult, type RichCaptionGeneratorConfig, type RichCaptionRendererOptions, type ShadowConfig, type ShapedLine, type ShapedWord, type ShapedWordGlyph, type ShotstackRichTextAsset, type ShotstackSvgAsset, type StrokeConfig, type StrokeSpec, type ValidAsset, type VideoEncoderCapabilities, type VideoEncoderConfig, type VideoEncoderProgress, WebCodecsEncoder, type WordAnimationConfig, type WordAnimationState, type WordTiming, WordTimingStore, arcToCubicBeziers, breakIntoLines, calculateAnimationStatesForGroup, commandsToPathString, computeSimplePathBounds, createDefaultGeneratorConfig, createFrameSchedule, createMediaRecorderFallback, createTextEngine, createVideoEncoder, createWebCodecsEncoder, createWebPainter, detectPlatform, detectSubtitleFormat, findWordAtTime, generateRichCaptionDrawOps, generateRichCaptionFrame, generateShapePathData, getDefaultAnimationConfig, getDrawCaptionWordOps, getEncoderCapabilities, getEncoderWarning, groupWordsByPause, initResvg, isDrawCaptionWordOp, isMediaRecorderSupported, isRTLText, isWebCodecsH264Supported, normalizePath, normalizePathString, parseSubtitleToWords, parseSvgPath, quadraticToCubic, renderSvgAssetToPng, renderSvgToPng, richCaptionAssetSchema, shapeToSvgString };
|