@bluepic/embed 0.4.0-next.90 → 0.4.0-next.91
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/bluepic-embed.iife.js +109 -109
- package/dist/bluepic-embed.umd.js +109 -109
- package/dist/components/fields/ImageEdit.vue.d.ts +7 -0
- package/dist/main.cjs +112 -112
- package/dist/main.d.ts +2 -0
- package/dist/main.mjs +40609 -39630
- package/dist/style.css +1 -1
- package/dist/util/autoCrop/applyAutoCrop.d.ts +20 -0
- package/dist/util/autoCrop/index.d.ts +5 -0
- package/dist/util/autoCrop/registry.d.ts +12 -0
- package/dist/util/autoCrop/solveAutoCrop.d.ts +39 -0
- package/dist/util/autoCrop/types.d.ts +29 -0
- package/dist/util/backgroundRemoval.d.ts +51 -0
- package/dist/util/cloudflareImages.d.ts +2 -0
- package/package.json +6 -4
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Template } from '@bluepic/types';
|
|
2
|
+
export type ApplyAutoCropOptions = {
|
|
3
|
+
src: string;
|
|
4
|
+
/** Natural dimensions as the field already resolved them. */
|
|
5
|
+
natural: {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
};
|
|
9
|
+
aspectRatio: number;
|
|
10
|
+
cropMode: Template.ImageValue['cropMode'];
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Full auto-crop pass for one image: load → detect → solve.
|
|
14
|
+
*
|
|
15
|
+
* Returns `null` for every "can't help here" case — no detector registered,
|
|
16
|
+
* image unreachable or not CORS-readable, no faces found, nothing worth
|
|
17
|
+
* proposing. Callers treat `null` as "keep the existing behaviour" and must
|
|
18
|
+
* not surface an error.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyAutoCrop(opts: ApplyAutoCropOptions): Promise<Template.Crop | null>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { FaceBox, FaceDetector } from './types';
|
|
2
|
+
export { solveAutoCrop, MIN_FACE_SCORE, FACE_VERTICAL_ANCHOR } from './solveAutoCrop';
|
|
3
|
+
export type { SolveAutoCropOptions } from './solveAutoCrop';
|
|
4
|
+
export { setFaceDetector, hasFaceDetector, detectFacesSafe } from './registry';
|
|
5
|
+
export { applyAutoCrop } from './applyAutoCrop';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FaceDetector, FaceBox } from './types';
|
|
2
|
+
export declare function setFaceDetector(next: FaceDetector | null): void;
|
|
3
|
+
export declare function hasFaceDetector(): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Run the registered detector, swallowing every failure.
|
|
6
|
+
*
|
|
7
|
+
* The `FaceDetector` contract already says "never throw", but this is the
|
|
8
|
+
* boundary between our code and a host-supplied function — so we enforce it
|
|
9
|
+
* here rather than trusting it. A rejected promise from a third-party
|
|
10
|
+
* detector must not be able to break an image upload.
|
|
11
|
+
*/
|
|
12
|
+
export declare function detectFacesSafe(source: ImageBitmap | HTMLImageElement | HTMLCanvasElement): Promise<FaceBox[]>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Template } from '@bluepic/types';
|
|
2
|
+
import type { FaceBox } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Faces below this confidence are ignored. Deliberately strict: a false
|
|
5
|
+
* positive silently reframes the user's image around a non-face, which is
|
|
6
|
+
* worse than not suggesting anything at all.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MIN_FACE_SCORE = 0.6;
|
|
9
|
+
/**
|
|
10
|
+
* Where the face centre should sit vertically inside the crop, as a fraction
|
|
11
|
+
* of crop height. 0.5 is dead centre and reads as "passport photo"; the rule
|
|
12
|
+
* of thirds puts eyes near the upper third, and ~0.4 for the face *centre*
|
|
13
|
+
* approximates that while staying safe for group shots.
|
|
14
|
+
*/
|
|
15
|
+
export declare const FACE_VERTICAL_ANCHOR = 0.4;
|
|
16
|
+
export type SolveAutoCropOptions = {
|
|
17
|
+
faces: FaceBox[];
|
|
18
|
+
/** Natural (unscaled) image dimensions in pixels. */
|
|
19
|
+
natural: {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
};
|
|
23
|
+
/** Target aspect ratio of the field (width / height). */
|
|
24
|
+
aspectRatio: number;
|
|
25
|
+
cropMode: Template.ImageValue['cropMode'];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Propose a crop rectangle that frames the detected faces.
|
|
29
|
+
*
|
|
30
|
+
* Returns `null` whenever there is nothing sensible to propose — no faces, a
|
|
31
|
+
* degenerate input, or a crop mode where cropping isn't what happens. `null`
|
|
32
|
+
* means "leave the existing default alone", never "error".
|
|
33
|
+
*
|
|
34
|
+
* The geometry mirrors what `cover` already does: the crop is the largest
|
|
35
|
+
* rectangle of the target ratio that fits inside the image (so no pixels are
|
|
36
|
+
* wasted), slid so the faces are well framed. It never zooms in — cropping
|
|
37
|
+
* tighter than necessary would throw away resolution the renderer wants.
|
|
38
|
+
*/
|
|
39
|
+
export declare function solveAutoCrop(opts: SolveAutoCropOptions): Template.Crop | null;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Face-detection contract for auto-crop.
|
|
3
|
+
*
|
|
4
|
+
* The embed deliberately ships NO detector implementation. It builds as a
|
|
5
|
+
* single-file IIFE/UMD bundle (see vite.config.ts `formats`), so a bundled
|
|
6
|
+
* onnxruntime-web would be inlined and shipped to every consumer whether or
|
|
7
|
+
* not they use auto-crop. The host app — which has real code-splitting —
|
|
8
|
+
* owns the runtime and registers it via `setFaceDetector`.
|
|
9
|
+
*
|
|
10
|
+
* That split also keeps the EU story intact: bx-template serves its own lazy
|
|
11
|
+
* chunk from template.bluepic.eu, so no CDN is involved.
|
|
12
|
+
*/
|
|
13
|
+
/** A detected face, in natural image pixels, origin top-left. */
|
|
14
|
+
export type FaceBox = {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
/** Detector confidence, 0..1. */
|
|
20
|
+
score: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Detects faces in an already-decoded image.
|
|
24
|
+
*
|
|
25
|
+
* Contract: must NEVER throw. Auto-crop is a convenience — a missing model,
|
|
26
|
+
* a WASM failure or a tainted canvas must degrade to "no suggestion", not to
|
|
27
|
+
* a failed upload. Return `[]` in all of those cases.
|
|
28
|
+
*/
|
|
29
|
+
export type FaceDetector = (source: ImageBitmap | HTMLImageElement | HTMLCanvasElement) => Promise<FaceBox[]>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type FieldsBridge } from '@bluepic/types';
|
|
2
|
+
/**
|
|
3
|
+
* The transform that performs background removal.
|
|
4
|
+
*
|
|
5
|
+
* `format: 'png'` is not optional dressing: `segment=foreground` writes
|
|
6
|
+
* transparent pixels, and without an alpha-capable output format Cloudflare
|
|
7
|
+
* flattens them — you'd pay for the transformation and get the original back.
|
|
8
|
+
*/
|
|
9
|
+
export declare const BACKGROUND_REMOVAL_TRANSFORM: {
|
|
10
|
+
readonly segment: "foreground";
|
|
11
|
+
readonly format: "png";
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Whether the host can actually perform Cloudflare Images transforms.
|
|
15
|
+
*
|
|
16
|
+
* Absent capabilities read as `false`: a bridge that predates this field
|
|
17
|
+
* demonstrably has no forwarding, so assuming "yes" would produce broken URLs.
|
|
18
|
+
*/
|
|
19
|
+
export declare function hostSupportsImageAi(bridge: Pick<FieldsBridge, 'capabilities'> | null | undefined): boolean;
|
|
20
|
+
export type ResolveBackgroundRemovalOptions = {
|
|
21
|
+
/** The field's `removeBackground` prop. */
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
/** Host capability — see `hostSupportsImageAi`. */
|
|
24
|
+
capable: boolean;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Decide the `src` an image field should store.
|
|
28
|
+
*
|
|
29
|
+
* Three properties this relies on, all provided by `withCloudflareTransform`:
|
|
30
|
+
*
|
|
31
|
+
* - **Idempotent** — safe to run on a src that already carries the transform,
|
|
32
|
+
* which happens on every re-render and every draft reload.
|
|
33
|
+
* - **Reversible** — turning the setting off restores the plain variant, so
|
|
34
|
+
* existing drafts follow the toggle instead of freezing at whatever they
|
|
35
|
+
* were uploaded with.
|
|
36
|
+
* - **Silent passthrough** — legacy R2 srcs, Pexels and shared-drive links
|
|
37
|
+
* are not delivery URLs and come back untouched rather than mangled.
|
|
38
|
+
*
|
|
39
|
+
* Never throws; the worst case is "the image is unchanged".
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveBackgroundRemoval(src: string, opts: ResolveBackgroundRemovalOptions): string;
|
|
42
|
+
/**
|
|
43
|
+
* The untransformed counterpart of a src, for use as an `<img>` error
|
|
44
|
+
* fallback.
|
|
45
|
+
*
|
|
46
|
+
* `segment=foreground` is a Cloudflare open beta. When it fails the browser
|
|
47
|
+
* renders a broken image, which is strictly worse than showing the original —
|
|
48
|
+
* so every surface that applies the transform should also be able to fall back.
|
|
49
|
+
* Returns `null` when there is nothing to fall back to.
|
|
50
|
+
*/
|
|
51
|
+
export declare function backgroundRemovalFallbackSrc(src: string): string | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bluepic/embed",
|
|
3
|
-
"version": "0.4.0-next.
|
|
3
|
+
"version": "0.4.0-next.91",
|
|
4
4
|
"description": "Bluepic embed sdk",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -29,14 +29,15 @@
|
|
|
29
29
|
"dev": "rimraf dist && concurrently \"npm:dev:vite\" \"npm:dev:types\"",
|
|
30
30
|
"dev:vite": "vite build --watch",
|
|
31
31
|
"dev:types": "vue-tsc -p tsconfig.build.json --declaration --emitDeclarationOnly --outDir dist --watch",
|
|
32
|
-
"playground:dev": "vite --config vite.playground.config.ts"
|
|
32
|
+
"playground:dev": "vite --config vite.playground.config.ts",
|
|
33
|
+
"test:autocrop": "tsx src/util/autoCrop/solveAutoCrop.test.ts"
|
|
33
34
|
},
|
|
34
35
|
"peerDependencies": {
|
|
35
36
|
"vue": "^3.5.23"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@auth0/auth0-vue": "^2.4.0",
|
|
39
|
-
"@bluepic/types": "^0.6.
|
|
40
|
+
"@bluepic/types": "^0.6.453",
|
|
40
41
|
"@hono/zod-openapi": "^1.1.4",
|
|
41
42
|
"@types/css": "^0.0.38",
|
|
42
43
|
"@types/downloadjs": "^1.4.6",
|
|
@@ -55,7 +56,8 @@
|
|
|
55
56
|
"vite": "^5.4.0",
|
|
56
57
|
"vue": "^3.5.27",
|
|
57
58
|
"vue-tsc": "^2.0.0",
|
|
58
|
-
"zod": "4.1.12"
|
|
59
|
+
"zod": "4.1.12",
|
|
60
|
+
"tsx": "^4.20.0"
|
|
59
61
|
},
|
|
60
62
|
"dependencies": {
|
|
61
63
|
"@bluepic/raster": "^0.1.6",
|