@remotion/web-renderer 4.0.429 → 4.0.430
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/add-sample.js +20 -0
- package/dist/artifact.js +56 -0
- package/dist/audio.js +42 -0
- package/dist/can-use-webfs-target.js +19 -0
- package/dist/compose.js +85 -0
- package/dist/create-scaffold.js +104 -0
- package/dist/drawing/border-radius.js +151 -0
- package/dist/drawing/calculate-object-fit.js +208 -0
- package/dist/drawing/calculate-transforms.js +127 -0
- package/dist/drawing/clamp-rect-to-parent-bounds.js +18 -0
- package/dist/drawing/do-rects-intersect.js +6 -0
- package/dist/drawing/draw-background.js +62 -0
- package/dist/drawing/draw-border.js +353 -0
- package/dist/drawing/draw-box-shadow.js +103 -0
- package/dist/drawing/draw-dom-element.js +85 -0
- package/dist/drawing/draw-element.js +84 -0
- package/dist/drawing/draw-outline.js +93 -0
- package/dist/drawing/draw-rounded.js +34 -0
- package/dist/drawing/drawn-fn.js +1 -0
- package/dist/drawing/fit-svg-into-its-dimensions.js +35 -0
- package/dist/drawing/get-clipped-background.d.ts +8 -0
- package/dist/drawing/get-clipped-background.js +14 -0
- package/dist/drawing/get-padding-box.js +30 -0
- package/dist/drawing/get-pretransform-rect.js +49 -0
- package/dist/drawing/handle-3d-transform.js +26 -0
- package/dist/drawing/handle-mask.js +21 -0
- package/dist/drawing/has-transform.js +14 -0
- package/dist/drawing/mask-image.js +14 -0
- package/dist/drawing/opacity.js +7 -0
- package/dist/drawing/overflow.js +14 -0
- package/dist/drawing/parse-linear-gradient.js +260 -0
- package/dist/drawing/parse-transform-origin.js +7 -0
- package/dist/drawing/precompose.d.ts +11 -0
- package/dist/drawing/precompose.js +14 -0
- package/dist/drawing/process-node.js +122 -0
- package/dist/drawing/round-to-expand-rect.js +7 -0
- package/dist/drawing/text/apply-text-transform.js +12 -0
- package/dist/drawing/text/draw-text.js +53 -0
- package/dist/drawing/text/find-line-breaks.text.js +118 -0
- package/dist/drawing/text/get-collapsed-text.d.ts +1 -0
- package/dist/drawing/text/get-collapsed-text.js +46 -0
- package/dist/drawing/text/handle-text-node.js +24 -0
- package/dist/drawing/text/parse-paint-order.d.ts +8 -0
- package/dist/drawing/transform-in-3d.js +177 -0
- package/dist/drawing/transform-rect-with-matrix.js +19 -0
- package/dist/drawing/transform.js +10 -0
- package/dist/drawing/turn-svg-into-drawable.js +41 -0
- package/dist/esm/index.mjs +34 -2
- package/dist/frame-range.js +15 -0
- package/dist/get-audio-encoding-config.js +18 -0
- package/dist/get-biggest-bounding-client-rect.js +43 -0
- package/dist/index.js +2 -0
- package/dist/internal-state.js +36 -0
- package/dist/mediabunny-mappings.js +63 -0
- package/dist/output-target.js +1 -0
- package/dist/props-if-has-props.js +1 -0
- package/dist/render-media-on-web.js +304 -0
- package/dist/render-operations-queue.js +3 -0
- package/dist/render-still-on-web.js +110 -0
- package/dist/send-telemetry-event.js +22 -0
- package/dist/take-screenshot.js +30 -0
- package/dist/throttle-progress.js +43 -0
- package/dist/tree-walker-cleanup-after-children.js +33 -0
- package/dist/update-time.js +17 -0
- package/dist/validate-video-frame.js +34 -0
- package/dist/wait-for-ready.js +39 -0
- package/dist/walk-tree.js +14 -0
- package/dist/web-fs-target.js +41 -0
- package/dist/with-resolvers.js +9 -0
- package/package.json +3 -2
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { processNode } from '../process-node';
|
|
2
|
+
import { drawText } from './draw-text';
|
|
3
|
+
export const handleTextNode = async ({ node, context, logLevel, parentRect, internalState, rootElement, onlyBackgroundClip, }) => {
|
|
4
|
+
const span = document.createElement('span');
|
|
5
|
+
const parent = node.parentNode;
|
|
6
|
+
if (!parent) {
|
|
7
|
+
throw new Error('Text node has no parent');
|
|
8
|
+
}
|
|
9
|
+
parent.insertBefore(span, node);
|
|
10
|
+
span.appendChild(node);
|
|
11
|
+
const value = await processNode({
|
|
12
|
+
context,
|
|
13
|
+
element: span,
|
|
14
|
+
draw: drawText({ span, logLevel, onlyBackgroundClip }),
|
|
15
|
+
logLevel,
|
|
16
|
+
parentRect,
|
|
17
|
+
internalState,
|
|
18
|
+
rootElement,
|
|
19
|
+
});
|
|
20
|
+
// Undo the layout manipulation
|
|
21
|
+
parent.insertBefore(node, span);
|
|
22
|
+
parent.removeChild(span);
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse paint-order CSS property to determine if stroke should be drawn before fill.
|
|
3
|
+
* Default order is: fill, stroke, markers
|
|
4
|
+
* paintOrder can be "normal", "fill", "stroke", "fill stroke", "stroke fill", etc.
|
|
5
|
+
*/
|
|
6
|
+
export declare const parsePaintOrder: (paintOrder: string) => {
|
|
7
|
+
strokeFirst: boolean;
|
|
8
|
+
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// Vertex shader - now includes texture coordinates
|
|
2
|
+
const vsSource = `
|
|
3
|
+
attribute vec2 aPosition;
|
|
4
|
+
attribute vec2 aTexCoord;
|
|
5
|
+
uniform mat4 uTransform;
|
|
6
|
+
uniform mat4 uProjection;
|
|
7
|
+
varying vec2 vTexCoord;
|
|
8
|
+
|
|
9
|
+
void main() {
|
|
10
|
+
gl_Position = uProjection * uTransform * vec4(aPosition, 0.0, 1.0);
|
|
11
|
+
vTexCoord = aTexCoord;
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
// Fragment shader - samples from texture and unpremultiplies alpha
|
|
15
|
+
const fsSource = `
|
|
16
|
+
precision mediump float;
|
|
17
|
+
uniform sampler2D uTexture;
|
|
18
|
+
varying vec2 vTexCoord;
|
|
19
|
+
|
|
20
|
+
void main() {
|
|
21
|
+
gl_FragColor = texture2D(uTexture, vTexCoord);
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
function compileShader(shaderGl, source, type) {
|
|
25
|
+
const shader = shaderGl.createShader(type);
|
|
26
|
+
if (!shader) {
|
|
27
|
+
throw new Error('Could not create shader');
|
|
28
|
+
}
|
|
29
|
+
shaderGl.shaderSource(shader, source);
|
|
30
|
+
shaderGl.compileShader(shader);
|
|
31
|
+
if (!shaderGl.getShaderParameter(shader, shaderGl.COMPILE_STATUS)) {
|
|
32
|
+
const log = shaderGl.getShaderInfoLog(shader);
|
|
33
|
+
shaderGl.deleteShader(shader);
|
|
34
|
+
throw new Error('Shader compile error: ' + log);
|
|
35
|
+
}
|
|
36
|
+
return shader;
|
|
37
|
+
}
|
|
38
|
+
const createHelperCanvas = ({ canvasWidth, canvasHeight, helperCanvasState, }) => {
|
|
39
|
+
var _a;
|
|
40
|
+
if (helperCanvasState.current) {
|
|
41
|
+
// Resize canvas if dimensions changed
|
|
42
|
+
if (helperCanvasState.current.canvas.width !== canvasWidth ||
|
|
43
|
+
helperCanvasState.current.canvas.height !== canvasHeight) {
|
|
44
|
+
helperCanvasState.current.canvas.width = canvasWidth;
|
|
45
|
+
helperCanvasState.current.canvas.height = canvasHeight;
|
|
46
|
+
}
|
|
47
|
+
// Always reset viewport and clear when reusing
|
|
48
|
+
helperCanvasState.current.gl.viewport(0, 0, canvasWidth, canvasHeight);
|
|
49
|
+
helperCanvasState.current.gl.clearColor(0, 0, 0, 0);
|
|
50
|
+
helperCanvasState.current.gl.clear(helperCanvasState.current.gl.COLOR_BUFFER_BIT);
|
|
51
|
+
return helperCanvasState.current;
|
|
52
|
+
}
|
|
53
|
+
const canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
|
|
54
|
+
const gl = (_a = canvas.getContext('webgl', {
|
|
55
|
+
premultipliedAlpha: true,
|
|
56
|
+
})) !== null && _a !== void 0 ? _a : undefined;
|
|
57
|
+
if (!gl) {
|
|
58
|
+
throw new Error('WebGL not supported');
|
|
59
|
+
}
|
|
60
|
+
// Compile shaders and create program once
|
|
61
|
+
const vertexShader = compileShader(gl, vsSource, gl.VERTEX_SHADER);
|
|
62
|
+
const fragmentShader = compileShader(gl, fsSource, gl.FRAGMENT_SHADER);
|
|
63
|
+
const program = gl.createProgram();
|
|
64
|
+
if (!program) {
|
|
65
|
+
throw new Error('Could not create program');
|
|
66
|
+
}
|
|
67
|
+
gl.attachShader(program, vertexShader);
|
|
68
|
+
gl.attachShader(program, fragmentShader);
|
|
69
|
+
gl.linkProgram(program);
|
|
70
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
71
|
+
throw new Error('Program link error: ' + gl.getProgramInfoLog(program));
|
|
72
|
+
}
|
|
73
|
+
// Get attribute and uniform locations once
|
|
74
|
+
const locations = {
|
|
75
|
+
aPosition: gl.getAttribLocation(program, 'aPosition'),
|
|
76
|
+
aTexCoord: gl.getAttribLocation(program, 'aTexCoord'),
|
|
77
|
+
uTransform: gl.getUniformLocation(program, 'uTransform'),
|
|
78
|
+
uProjection: gl.getUniformLocation(program, 'uProjection'),
|
|
79
|
+
uTexture: gl.getUniformLocation(program, 'uTexture'),
|
|
80
|
+
};
|
|
81
|
+
// Shaders can be deleted after linking
|
|
82
|
+
gl.deleteShader(vertexShader);
|
|
83
|
+
gl.deleteShader(fragmentShader);
|
|
84
|
+
const cleanup = () => {
|
|
85
|
+
gl.deleteProgram(program);
|
|
86
|
+
const loseContext = gl.getExtension('WEBGL_lose_context');
|
|
87
|
+
if (loseContext) {
|
|
88
|
+
loseContext.loseContext();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
helperCanvasState.current = { canvas, gl, program, locations, cleanup };
|
|
92
|
+
return helperCanvasState.current;
|
|
93
|
+
};
|
|
94
|
+
export const transformIn3d = ({ matrix, sourceCanvas, untransformedRect, rectAfterTransforms, internalState, }) => {
|
|
95
|
+
const { canvas, gl, program, locations } = createHelperCanvas({
|
|
96
|
+
canvasWidth: rectAfterTransforms.width,
|
|
97
|
+
canvasHeight: rectAfterTransforms.height,
|
|
98
|
+
helperCanvasState: internalState.helperCanvasState,
|
|
99
|
+
});
|
|
100
|
+
// Use the cached program
|
|
101
|
+
gl.useProgram(program);
|
|
102
|
+
// Setup viewport and clear (already done in createHelperCanvas, but ensure it's set)
|
|
103
|
+
gl.viewport(0, 0, rectAfterTransforms.width, rectAfterTransforms.height);
|
|
104
|
+
gl.clearColor(0, 0, 0, 0);
|
|
105
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
106
|
+
// Enable blending
|
|
107
|
+
gl.enable(gl.BLEND);
|
|
108
|
+
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
109
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
110
|
+
// Create vertex buffer
|
|
111
|
+
const vertexBuffer = gl.createBuffer();
|
|
112
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
113
|
+
// prettier-ignore
|
|
114
|
+
const vertices = new Float32Array([
|
|
115
|
+
untransformedRect.x, untransformedRect.y, 0, 0,
|
|
116
|
+
untransformedRect.x + untransformedRect.width, untransformedRect.y, 1, 0,
|
|
117
|
+
untransformedRect.x, untransformedRect.y + untransformedRect.height, 0, 1,
|
|
118
|
+
untransformedRect.x, untransformedRect.y + untransformedRect.height, 0, 1,
|
|
119
|
+
untransformedRect.x + untransformedRect.width, untransformedRect.y, 1, 0,
|
|
120
|
+
untransformedRect.x + untransformedRect.width, untransformedRect.y + untransformedRect.height, 1, 1,
|
|
121
|
+
]);
|
|
122
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
|
123
|
+
// Setup attributes using cached locations
|
|
124
|
+
gl.enableVertexAttribArray(locations.aPosition);
|
|
125
|
+
gl.vertexAttribPointer(locations.aPosition, 2, gl.FLOAT, false, 4 * 4, 0);
|
|
126
|
+
gl.enableVertexAttribArray(locations.aTexCoord);
|
|
127
|
+
gl.vertexAttribPointer(locations.aTexCoord, 2, gl.FLOAT, false, 4 * 4, 2 * 4);
|
|
128
|
+
// Create and configure texture
|
|
129
|
+
const texture = gl.createTexture();
|
|
130
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
131
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
132
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
133
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
134
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
135
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, sourceCanvas);
|
|
136
|
+
// Set uniforms using cached locations
|
|
137
|
+
const transformMatrix = matrix.toFloat32Array();
|
|
138
|
+
const zScale = 1000000000;
|
|
139
|
+
// Projection matrix accounts for the output canvas dimensions
|
|
140
|
+
const projectionMatrix = new Float32Array([
|
|
141
|
+
2 / rectAfterTransforms.width,
|
|
142
|
+
0,
|
|
143
|
+
0,
|
|
144
|
+
0,
|
|
145
|
+
0,
|
|
146
|
+
-2 / rectAfterTransforms.height,
|
|
147
|
+
0,
|
|
148
|
+
0,
|
|
149
|
+
0,
|
|
150
|
+
0,
|
|
151
|
+
-2 / zScale,
|
|
152
|
+
0,
|
|
153
|
+
-1 + (2 * -rectAfterTransforms.x) / rectAfterTransforms.width,
|
|
154
|
+
1 - (2 * -rectAfterTransforms.y) / rectAfterTransforms.height,
|
|
155
|
+
0,
|
|
156
|
+
1,
|
|
157
|
+
]);
|
|
158
|
+
gl.uniformMatrix4fv(locations.uTransform, false, transformMatrix);
|
|
159
|
+
gl.uniformMatrix4fv(locations.uProjection, false, projectionMatrix);
|
|
160
|
+
gl.uniform1i(locations.uTexture, 0);
|
|
161
|
+
// Draw
|
|
162
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
163
|
+
// Clean up per-frame resources only
|
|
164
|
+
gl.disableVertexAttribArray(locations.aPosition);
|
|
165
|
+
gl.disableVertexAttribArray(locations.aTexCoord);
|
|
166
|
+
gl.deleteTexture(texture);
|
|
167
|
+
gl.deleteBuffer(vertexBuffer);
|
|
168
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
169
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
170
|
+
// Reset state
|
|
171
|
+
gl.disable(gl.BLEND);
|
|
172
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
173
|
+
return {
|
|
174
|
+
canvas,
|
|
175
|
+
rect: rectAfterTransforms,
|
|
176
|
+
};
|
|
177
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function transformDOMRect({ rect, matrix, }) {
|
|
2
|
+
// Get all four corners of the rectangle
|
|
3
|
+
const topLeft = new DOMPointReadOnly(rect.left, rect.top);
|
|
4
|
+
const topRight = new DOMPointReadOnly(rect.right, rect.top);
|
|
5
|
+
const bottomLeft = new DOMPointReadOnly(rect.left, rect.bottom);
|
|
6
|
+
const bottomRight = new DOMPointReadOnly(rect.right, rect.bottom);
|
|
7
|
+
// Transform all corners
|
|
8
|
+
const transformedTopLeft = topLeft.matrixTransform(matrix);
|
|
9
|
+
const transformedTopRight = topRight.matrixTransform(matrix);
|
|
10
|
+
const transformedBottomLeft = bottomLeft.matrixTransform(matrix);
|
|
11
|
+
const transformedBottomRight = bottomRight.matrixTransform(matrix);
|
|
12
|
+
// Find the bounding box of the transformed points
|
|
13
|
+
const minX = Math.min(transformedTopLeft.x / transformedTopLeft.w, transformedTopRight.x / transformedTopRight.w, transformedBottomLeft.x / transformedBottomLeft.w, transformedBottomRight.x / transformedBottomRight.w);
|
|
14
|
+
const maxX = Math.max(transformedTopLeft.x / transformedTopLeft.w, transformedTopRight.x / transformedTopRight.w, transformedBottomLeft.x / transformedBottomLeft.w, transformedBottomRight.x / transformedBottomRight.w);
|
|
15
|
+
const minY = Math.min(transformedTopLeft.y / transformedTopLeft.w, transformedTopRight.y / transformedTopRight.w, transformedBottomLeft.y / transformedBottomLeft.w, transformedBottomRight.y / transformedBottomRight.w);
|
|
16
|
+
const maxY = Math.max(transformedTopLeft.y / transformedTopLeft.w, transformedTopRight.y / transformedTopRight.w, transformedBottomLeft.y / transformedBottomLeft.w, transformedBottomRight.y / transformedBottomRight.w);
|
|
17
|
+
// Create a new DOMRect from the bounding box
|
|
18
|
+
return new DOMRect(minX, minY, maxX - minX, maxY - minY);
|
|
19
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const setTransform = ({ ctx, transform, parentRect, }) => {
|
|
2
|
+
const offsetMatrix = new DOMMatrix()
|
|
3
|
+
.translate(-parentRect.x, -parentRect.y)
|
|
4
|
+
.multiply(transform)
|
|
5
|
+
.translate(parentRect.x, parentRect.y);
|
|
6
|
+
ctx.setTransform(offsetMatrix);
|
|
7
|
+
return () => {
|
|
8
|
+
ctx.setTransform(new DOMMatrix());
|
|
9
|
+
};
|
|
10
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const turnSvgIntoDrawable = (svg) => {
|
|
2
|
+
const { fill, color } = getComputedStyle(svg);
|
|
3
|
+
const originalTransform = svg.style.transform;
|
|
4
|
+
const originalTransformOrigin = svg.style.transformOrigin;
|
|
5
|
+
const originalMarginLeft = svg.style.marginLeft;
|
|
6
|
+
const originalMarginRight = svg.style.marginRight;
|
|
7
|
+
const originalMarginTop = svg.style.marginTop;
|
|
8
|
+
const originalMarginBottom = svg.style.marginBottom;
|
|
9
|
+
const originalFill = svg.style.fill;
|
|
10
|
+
const originalColor = svg.style.color;
|
|
11
|
+
svg.style.transform = 'none';
|
|
12
|
+
svg.style.transformOrigin = '';
|
|
13
|
+
// Margins were already included in the positioning calculation,
|
|
14
|
+
// so we need to remove them to avoid double counting.
|
|
15
|
+
svg.style.marginLeft = '0';
|
|
16
|
+
svg.style.marginRight = '0';
|
|
17
|
+
svg.style.marginTop = '0';
|
|
18
|
+
svg.style.marginBottom = '0';
|
|
19
|
+
svg.style.fill = fill;
|
|
20
|
+
svg.style.color = color;
|
|
21
|
+
const svgData = new XMLSerializer().serializeToString(svg);
|
|
22
|
+
svg.style.marginLeft = originalMarginLeft;
|
|
23
|
+
svg.style.marginRight = originalMarginRight;
|
|
24
|
+
svg.style.marginTop = originalMarginTop;
|
|
25
|
+
svg.style.marginBottom = originalMarginBottom;
|
|
26
|
+
svg.style.transform = originalTransform;
|
|
27
|
+
svg.style.transformOrigin = originalTransformOrigin;
|
|
28
|
+
svg.style.fill = originalFill;
|
|
29
|
+
svg.style.color = originalColor;
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const image = new Image();
|
|
32
|
+
const url = `data:image/svg+xml;base64,${btoa(svgData)}`;
|
|
33
|
+
image.onload = function () {
|
|
34
|
+
resolve(image);
|
|
35
|
+
};
|
|
36
|
+
image.onerror = () => {
|
|
37
|
+
reject(new Error('Failed to convert SVG to image'));
|
|
38
|
+
};
|
|
39
|
+
image.src = url;
|
|
40
|
+
});
|
|
41
|
+
};
|
package/dist/esm/index.mjs
CHANGED
|
@@ -3308,6 +3308,16 @@ var findWords = (span) => {
|
|
|
3308
3308
|
return tokens;
|
|
3309
3309
|
};
|
|
3310
3310
|
|
|
3311
|
+
// src/drawing/text/parse-paint-order.ts
|
|
3312
|
+
var parsePaintOrder = (paintOrder) => {
|
|
3313
|
+
const paintOrderValue = paintOrder || "normal";
|
|
3314
|
+
const paintOrderParts = paintOrderValue === "normal" ? ["fill", "stroke"] : paintOrderValue.split(/\s+/).filter(Boolean);
|
|
3315
|
+
const strokeIndex = paintOrderParts.indexOf("stroke");
|
|
3316
|
+
const fillIndex = paintOrderParts.indexOf("fill");
|
|
3317
|
+
const strokeFirst = strokeIndex !== -1 && (fillIndex === -1 || strokeIndex < fillIndex);
|
|
3318
|
+
return { strokeFirst };
|
|
3319
|
+
};
|
|
3320
|
+
|
|
3311
3321
|
// src/drawing/text/parse-text-shadow.ts
|
|
3312
3322
|
var parseTextShadow = (textShadowValue) => {
|
|
3313
3323
|
return parseShadowValues(textShadowValue);
|
|
@@ -3331,7 +3341,10 @@ var drawText = ({
|
|
|
3331
3341
|
letterSpacing,
|
|
3332
3342
|
textTransform,
|
|
3333
3343
|
webkitTextFillColor,
|
|
3334
|
-
|
|
3344
|
+
webkitTextStrokeWidth,
|
|
3345
|
+
webkitTextStrokeColor,
|
|
3346
|
+
textShadow: textShadowValue,
|
|
3347
|
+
paintOrder
|
|
3335
3348
|
} = computedStyle;
|
|
3336
3349
|
const isVertical = writingMode !== "horizontal-tb";
|
|
3337
3350
|
if (isVertical) {
|
|
@@ -3346,6 +3359,12 @@ var drawText = ({
|
|
|
3346
3359
|
contextToDraw.font = `${fontStyle} ${fontWeight} ${fontSizePx}px ${fontFamily}`;
|
|
3347
3360
|
contextToDraw.fillStyle = onlyBackgroundClipText ? "black" : webkitTextFillColor;
|
|
3348
3361
|
contextToDraw.letterSpacing = letterSpacing;
|
|
3362
|
+
const strokeWidth = parseFloat(webkitTextStrokeWidth);
|
|
3363
|
+
const hasStroke = strokeWidth > 0;
|
|
3364
|
+
if (hasStroke) {
|
|
3365
|
+
contextToDraw.strokeStyle = webkitTextStrokeColor;
|
|
3366
|
+
contextToDraw.lineWidth = strokeWidth;
|
|
3367
|
+
}
|
|
3349
3368
|
const isRTL = direction === "rtl";
|
|
3350
3369
|
contextToDraw.textAlign = isRTL ? "right" : "left";
|
|
3351
3370
|
contextToDraw.textBaseline = "alphabetic";
|
|
@@ -3354,6 +3373,7 @@ var drawText = ({
|
|
|
3354
3373
|
span.textContent = transformedText;
|
|
3355
3374
|
const tokens = findWords(span);
|
|
3356
3375
|
const textShadows = parseTextShadow(textShadowValue);
|
|
3376
|
+
const { strokeFirst } = parsePaintOrder(paintOrder);
|
|
3357
3377
|
for (const token of tokens) {
|
|
3358
3378
|
const measurements = contextToDraw.measureText(originalText);
|
|
3359
3379
|
const { fontBoundingBoxDescent, fontBoundingBoxAscent } = measurements;
|
|
@@ -3374,7 +3394,19 @@ var drawText = ({
|
|
|
3374
3394
|
contextToDraw.shadowBlur = 0;
|
|
3375
3395
|
contextToDraw.shadowOffsetX = 0;
|
|
3376
3396
|
contextToDraw.shadowOffsetY = 0;
|
|
3377
|
-
contextToDraw.fillText(token.text, x, y);
|
|
3397
|
+
const drawFill = () => contextToDraw.fillText(token.text, x, y);
|
|
3398
|
+
const drawStroke = () => {
|
|
3399
|
+
if (hasStroke) {
|
|
3400
|
+
contextToDraw.strokeText(token.text, x, y);
|
|
3401
|
+
}
|
|
3402
|
+
};
|
|
3403
|
+
if (strokeFirst) {
|
|
3404
|
+
drawStroke();
|
|
3405
|
+
drawFill();
|
|
3406
|
+
} else {
|
|
3407
|
+
drawFill();
|
|
3408
|
+
drawStroke();
|
|
3409
|
+
}
|
|
3378
3410
|
}
|
|
3379
3411
|
span.textContent = originalText;
|
|
3380
3412
|
contextToDraw.restore();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const getRealFrameRange = (durationInFrames, frameRange) => {
|
|
2
|
+
if (frameRange === null) {
|
|
3
|
+
return [0, durationInFrames - 1];
|
|
4
|
+
}
|
|
5
|
+
if (typeof frameRange === 'number') {
|
|
6
|
+
if (frameRange < 0 || frameRange >= durationInFrames) {
|
|
7
|
+
throw new Error(`Frame number is out of range, must be between 0 and ${durationInFrames - 1} but got ${frameRange}`);
|
|
8
|
+
}
|
|
9
|
+
return [frameRange, frameRange];
|
|
10
|
+
}
|
|
11
|
+
if (frameRange[1] >= durationInFrames || frameRange[0] < 0) {
|
|
12
|
+
throw new Error(`The "durationInFrames" of the composition was evaluated to be ${durationInFrames}, but frame range ${frameRange.join('-')} is not inbetween 0-${durationInFrames - 1}`);
|
|
13
|
+
}
|
|
14
|
+
return frameRange;
|
|
15
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { canEncodeAudio, QUALITY_MEDIUM, } from 'mediabunny';
|
|
2
|
+
export const getDefaultAudioEncodingConfig = async () => {
|
|
3
|
+
const preferredDefaultAudioEncodingConfig = {
|
|
4
|
+
codec: 'aac',
|
|
5
|
+
bitrate: QUALITY_MEDIUM,
|
|
6
|
+
};
|
|
7
|
+
if (await canEncodeAudio(preferredDefaultAudioEncodingConfig.codec, preferredDefaultAudioEncodingConfig)) {
|
|
8
|
+
return preferredDefaultAudioEncodingConfig;
|
|
9
|
+
}
|
|
10
|
+
const backupDefaultAudioEncodingConfig = {
|
|
11
|
+
codec: 'opus',
|
|
12
|
+
bitrate: QUALITY_MEDIUM,
|
|
13
|
+
};
|
|
14
|
+
if (await canEncodeAudio(backupDefaultAudioEncodingConfig.codec, backupDefaultAudioEncodingConfig)) {
|
|
15
|
+
return backupDefaultAudioEncodingConfig;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { parseBoxShadow } from './drawing/draw-box-shadow';
|
|
2
|
+
import { parseOutlineOffset, parseOutlineWidth } from './drawing/draw-outline';
|
|
3
|
+
import { skipToNextNonDescendant } from './walk-tree';
|
|
4
|
+
export const getBiggestBoundingClientRect = (element) => {
|
|
5
|
+
const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
|
|
6
|
+
let mostLeft = Infinity;
|
|
7
|
+
let mostTop = Infinity;
|
|
8
|
+
let mostRight = -Infinity;
|
|
9
|
+
let mostBottom = -Infinity;
|
|
10
|
+
while (true) {
|
|
11
|
+
const computedStyle = getComputedStyle(treeWalker.currentNode);
|
|
12
|
+
const outlineWidth = parseOutlineWidth(computedStyle.outlineWidth);
|
|
13
|
+
const outlineOffset = parseOutlineOffset(computedStyle.outlineOffset);
|
|
14
|
+
const rect = treeWalker.currentNode.getBoundingClientRect();
|
|
15
|
+
// Calculate box shadow extensions
|
|
16
|
+
const shadows = parseBoxShadow(computedStyle.boxShadow);
|
|
17
|
+
let shadowLeft = 0;
|
|
18
|
+
let shadowRight = 0;
|
|
19
|
+
let shadowTop = 0;
|
|
20
|
+
let shadowBottom = 0;
|
|
21
|
+
for (const shadow of shadows) {
|
|
22
|
+
if (!shadow.inset) {
|
|
23
|
+
shadowLeft = Math.max(shadowLeft, Math.abs(Math.min(shadow.offsetX, 0)) + shadow.blurRadius);
|
|
24
|
+
shadowRight = Math.max(shadowRight, Math.max(shadow.offsetX, 0) + shadow.blurRadius);
|
|
25
|
+
shadowTop = Math.max(shadowTop, Math.abs(Math.min(shadow.offsetY, 0)) + shadow.blurRadius);
|
|
26
|
+
shadowBottom = Math.max(shadowBottom, Math.max(shadow.offsetY, 0) + shadow.blurRadius);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
mostLeft = Math.min(mostLeft, rect.left - outlineOffset - outlineWidth - shadowLeft);
|
|
30
|
+
mostTop = Math.min(mostTop, rect.top - outlineOffset - outlineWidth - shadowTop);
|
|
31
|
+
mostRight = Math.max(mostRight, rect.right + outlineOffset + outlineWidth + shadowRight);
|
|
32
|
+
mostBottom = Math.max(mostBottom, rect.bottom + outlineOffset + outlineWidth + shadowBottom);
|
|
33
|
+
if (computedStyle.overflow === 'hidden') {
|
|
34
|
+
if (!skipToNextNonDescendant(treeWalker)) {
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!treeWalker.nextNode()) {
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return new DOMRect(mostLeft, mostTop, mostRight - mostLeft, mostBottom - mostTop);
|
|
43
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const makeInternalState = () => {
|
|
2
|
+
let drawnPrecomposedPixels = 0;
|
|
3
|
+
let precomposedTextures = 0;
|
|
4
|
+
let waitForReadyTime = 0;
|
|
5
|
+
let addSampleTime = 0;
|
|
6
|
+
let createFrameTime = 0;
|
|
7
|
+
const helperCanvasState = {
|
|
8
|
+
current: null,
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
getDrawn3dPixels: () => drawnPrecomposedPixels,
|
|
12
|
+
getPrecomposedTiles: () => precomposedTextures,
|
|
13
|
+
addPrecompose: ({ canvasWidth, canvasHeight, }) => {
|
|
14
|
+
drawnPrecomposedPixels += canvasWidth * canvasHeight;
|
|
15
|
+
precomposedTextures++;
|
|
16
|
+
},
|
|
17
|
+
helperCanvasState,
|
|
18
|
+
cleanup: () => {
|
|
19
|
+
if (helperCanvasState.current) {
|
|
20
|
+
helperCanvasState.current.cleanup();
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
getWaitForReadyTime: () => waitForReadyTime,
|
|
24
|
+
addWaitForReadyTime: (time) => {
|
|
25
|
+
waitForReadyTime += time;
|
|
26
|
+
},
|
|
27
|
+
getAddSampleTime: () => addSampleTime,
|
|
28
|
+
addAddSampleTime: (time) => {
|
|
29
|
+
addSampleTime += time;
|
|
30
|
+
},
|
|
31
|
+
getCreateFrameTime: () => createFrameTime,
|
|
32
|
+
addCreateFrameTime: (time) => {
|
|
33
|
+
createFrameTime += time;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Mp4OutputFormat, QUALITY_HIGH, QUALITY_LOW, QUALITY_MEDIUM, QUALITY_VERY_HIGH, QUALITY_VERY_LOW, WebMOutputFormat, } from 'mediabunny';
|
|
2
|
+
export const codecToMediabunnyCodec = (codec) => {
|
|
3
|
+
switch (codec) {
|
|
4
|
+
case 'h264':
|
|
5
|
+
return 'avc';
|
|
6
|
+
case 'h265':
|
|
7
|
+
return 'hevc';
|
|
8
|
+
case 'vp8':
|
|
9
|
+
return 'vp8';
|
|
10
|
+
case 'vp9':
|
|
11
|
+
return 'vp9';
|
|
12
|
+
case 'av1':
|
|
13
|
+
return 'av1';
|
|
14
|
+
default:
|
|
15
|
+
throw new Error(`Unsupported codec: ${codec}`);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export const containerToMediabunnyContainer = (container) => {
|
|
19
|
+
switch (container) {
|
|
20
|
+
case 'mp4':
|
|
21
|
+
return new Mp4OutputFormat();
|
|
22
|
+
case 'webm':
|
|
23
|
+
return new WebMOutputFormat();
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export const getDefaultVideoCodecForContainer = (container) => {
|
|
29
|
+
switch (container) {
|
|
30
|
+
case 'mp4':
|
|
31
|
+
return 'h264';
|
|
32
|
+
case 'webm':
|
|
33
|
+
return 'vp8';
|
|
34
|
+
default:
|
|
35
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
export const getQualityForWebRendererQuality = (quality) => {
|
|
39
|
+
switch (quality) {
|
|
40
|
+
case 'very-low':
|
|
41
|
+
return QUALITY_VERY_LOW;
|
|
42
|
+
case 'low':
|
|
43
|
+
return QUALITY_LOW;
|
|
44
|
+
case 'medium':
|
|
45
|
+
return QUALITY_MEDIUM;
|
|
46
|
+
case 'high':
|
|
47
|
+
return QUALITY_HIGH;
|
|
48
|
+
case 'very-high':
|
|
49
|
+
return QUALITY_VERY_HIGH;
|
|
50
|
+
default:
|
|
51
|
+
throw new Error(`Unsupported quality: ${quality}`);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
export const getMimeType = (container) => {
|
|
55
|
+
switch (container) {
|
|
56
|
+
case 'mp4':
|
|
57
|
+
return 'video/mp4';
|
|
58
|
+
case 'webm':
|
|
59
|
+
return 'video/webm';
|
|
60
|
+
default:
|
|
61
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|