@maravilla-labs/platform 0.15.0 → 0.16.0
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/CHANGELOG.md +27 -0
- package/dist/config.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +39 -1
- package/dist/index.js.map +1 -1
- package/dist/{transforms-BPrlJoYd.d.ts → transforms-DkAlUPu6.d.ts} +92 -1
- package/package.json +1 -1
- package/src/transforms.ts +143 -0
- package/tests/focal-css.test.ts +106 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @maravilla-labs/platform
|
|
2
2
|
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4b6b127: Add a `zoom` option to `resize({ crop: 'focal' })` for face-box-relative crop
|
|
8
|
+
framing. Until now a focal crop only centered a fixed-size window on the stored
|
|
9
|
+
focal _point_ — the detected face's bounding-box size was discarded, so there
|
|
10
|
+
was no way to control how tightly the subject was framed. `zoom` (a scale
|
|
11
|
+
factor, `1.0..=100.0`) now sizes the crop window from the union of the source's
|
|
12
|
+
detected faces: `1.0` frames tightly (a headshot), larger pulls back for
|
|
13
|
+
headroom/context, and a value large enough to exceed the image saturates to the
|
|
14
|
+
plain scale-to-cover crop. It's declarable in the `maravilla.config.ts`
|
|
15
|
+
`transforms` block too.
|
|
16
|
+
|
|
17
|
+
Fully backward compatible: `zoom` is optional and never serializes when omitted,
|
|
18
|
+
so every existing focal/center crop hashes to the same derived key and is
|
|
19
|
+
byte-identical. `zoom` is only honoured for `crop: 'focal'` on a source that has
|
|
20
|
+
stored face data (run `detectFaces` first); it's ignored for `crop: 'center'`
|
|
21
|
+
and a no-op when no faces were detected.
|
|
22
|
+
|
|
23
|
+
Also adds two pure, isomorphic, framework-agnostic helpers to
|
|
24
|
+
`@maravilla-labs/platform` — `focalCssFrame()` and `unionFaceBox()` — the
|
|
25
|
+
browser-side counterpart to the server crop: they turn a source's focal
|
|
26
|
+
point + detected faces into `object-position` + `transform: scale` CSS values,
|
|
27
|
+
so one `<img>` can re-frame around the face(s) for any container aspect ratio
|
|
28
|
+
and zoom without a server round-trip or a pre-rendered crop per shape.
|
|
29
|
+
|
|
3
30
|
## 0.15.0
|
|
4
31
|
|
|
5
32
|
### Minor Changes
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as TransformsConfig } from './transforms-
|
|
2
|
-
export { a as TransformsPatternSpec } from './transforms-
|
|
1
|
+
import { T as TransformsConfig } from './transforms-DkAlUPu6.js';
|
|
2
|
+
export { a as TransformsPatternSpec } from './transforms-DkAlUPu6.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @fileoverview Typed schema for `maravilla.config.{ts,yaml,json}` files.
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { ActAsContext, AddCircleMemberOptions, AddRelationOptions, ApiKeyInfo, A
|
|
|
3
3
|
export { b as RenClient, a as RenClientOptions, R as RenEvent, g as getOrCreateClientId, r as renFetch, c as storageDelete, s as storageUpload } from './ren-DetHRhCL.js';
|
|
4
4
|
import { LocalParticipant } from 'livekit-client';
|
|
5
5
|
export { RegisterPushOptions, RegisterPushResult, offsetBefore, registerPush, unregisterPush } from './push.js';
|
|
6
|
-
export { D as DetachAudioOpts, e as DetectFacesOpts, l as DocConvertOpts, i as DocFormat, q as DocInsertQrCodeOpts, p as DocReplaceImagesOpts, s as DocTemplateMergeOpts, k as DocThumbnailOpts, n as DocToHtmlOpts, m as DocToMarkdownOpts, j as DocToPdfOpts, d as ExtractAudioOpts, E as ExtractFramesOpts, g as FaceBox, f as FocalPoint, h as FocalPointRecord, F as FramesetManifest, I as ImageFormat, o as ImageRef, u as JobHandle, J as JobStatus, v as JobStatusResponse, M as MediaInfo, O as OcrOpts, Q as QrCodeSpec, r as QrPayload, R as ResizeOpts, c as ThumbnailOpts, b as TranscodeOpts, t as TransformSpec, T as TransformsConfig, a as TransformsPatternSpec, w as TransformsService, V as VideoFormat, x as keyFor,
|
|
6
|
+
export { D as DetachAudioOpts, e as DetectFacesOpts, l as DocConvertOpts, i as DocFormat, q as DocInsertQrCodeOpts, p as DocReplaceImagesOpts, s as DocTemplateMergeOpts, k as DocThumbnailOpts, n as DocToHtmlOpts, m as DocToMarkdownOpts, j as DocToPdfOpts, d as ExtractAudioOpts, E as ExtractFramesOpts, g as FaceBox, z as FocalCssFrame, y as FocalCssFrameInput, f as FocalPoint, h as FocalPointRecord, F as FramesetManifest, I as ImageFormat, o as ImageRef, u as JobHandle, J as JobStatus, v as JobStatusResponse, M as MediaInfo, O as OcrOpts, Q as QrCodeSpec, r as QrPayload, R as ResizeOpts, S as SubjectBox, c as ThumbnailOpts, b as TranscodeOpts, t as TransformSpec, T as TransformsConfig, a as TransformsPatternSpec, w as TransformsService, V as VideoFormat, B as focalCssFrame, x as keyFor, C as transforms, A as unionFaceBox } from './transforms-DkAlUPu6.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Media service for video/audio room management.
|
package/dist/index.js
CHANGED
|
@@ -2096,8 +2096,44 @@ function keyFor(srcKey, spec) {
|
|
|
2096
2096
|
const ext = outputExtension(spec);
|
|
2097
2097
|
return `__derived/${srcHash}/${variantHash}.${ext}`;
|
|
2098
2098
|
}
|
|
2099
|
+
var clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
2100
|
+
function unionFaceBox(faces) {
|
|
2101
|
+
if (!faces || faces.length === 0) return null;
|
|
2102
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
2103
|
+
for (const f of faces) {
|
|
2104
|
+
x0 = Math.min(x0, f.x);
|
|
2105
|
+
y0 = Math.min(y0, f.y);
|
|
2106
|
+
x1 = Math.max(x1, f.x + f.w);
|
|
2107
|
+
y1 = Math.max(y1, f.y + f.h);
|
|
2108
|
+
}
|
|
2109
|
+
x0 = clamp01(x0);
|
|
2110
|
+
y0 = clamp01(y0);
|
|
2111
|
+
x1 = clamp01(x1);
|
|
2112
|
+
y1 = clamp01(y1);
|
|
2113
|
+
const w = x1 - x0;
|
|
2114
|
+
const h = y1 - y0;
|
|
2115
|
+
if (w <= 0 || h <= 0) return null;
|
|
2116
|
+
return { x: x0, y: y0, w, h };
|
|
2117
|
+
}
|
|
2118
|
+
function focalCssFrame(input) {
|
|
2119
|
+
const { focal, faces, imgWidth, imgHeight, containerAspect } = input;
|
|
2120
|
+
const zoom = input.zoom ?? 1;
|
|
2121
|
+
const objectPosition = `${(clamp01(focal.x) * 100).toFixed(1)}% ${(clamp01(focal.y) * 100).toFixed(1)}%`;
|
|
2122
|
+
const base = { objectPosition, scale: 1, transformOrigin: objectPosition };
|
|
2123
|
+
const box = unionFaceBox(faces);
|
|
2124
|
+
if (!box || imgWidth <= 0 || imgHeight <= 0 || !(containerAspect > 0)) return base;
|
|
2125
|
+
const iar = imgWidth / imgHeight;
|
|
2126
|
+
const car = containerAspect;
|
|
2127
|
+
const z = Math.max(1, zoom);
|
|
2128
|
+
const targetW = z * Math.max(box.w, box.h * car / iar);
|
|
2129
|
+
const coverW = car >= iar ? 1 : car / iar;
|
|
2130
|
+
const scale = Math.max(1, coverW / targetW);
|
|
2131
|
+
return { objectPosition, scale: Math.round(scale * 1e3) / 1e3, transformOrigin: objectPosition };
|
|
2132
|
+
}
|
|
2099
2133
|
var transforms = {
|
|
2100
|
-
keyFor
|
|
2134
|
+
keyFor,
|
|
2135
|
+
focalCssFrame,
|
|
2136
|
+
unionFaceBox
|
|
2101
2137
|
};
|
|
2102
2138
|
|
|
2103
2139
|
// src/index.ts
|
|
@@ -2144,6 +2180,7 @@ export {
|
|
|
2144
2180
|
attachTrack,
|
|
2145
2181
|
clearPlatformCache,
|
|
2146
2182
|
detachTrack,
|
|
2183
|
+
focalCssFrame,
|
|
2147
2184
|
getCurrentRequestStore,
|
|
2148
2185
|
getOrCreateClientId,
|
|
2149
2186
|
getPlatform,
|
|
@@ -2155,6 +2192,7 @@ export {
|
|
|
2155
2192
|
storageDelete,
|
|
2156
2193
|
storageUpload,
|
|
2157
2194
|
transforms,
|
|
2195
|
+
unionFaceBox,
|
|
2158
2196
|
unregisterPush
|
|
2159
2197
|
};
|
|
2160
2198
|
//# sourceMappingURL=index.js.map
|