@imgly/plugin-background-removal-web 0.2.0 → 0.3.0-rc.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/README.md +101 -17
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +4 -4
- package/dist/plugin.d.ts +3 -2
- package/dist/processBackgroundRemoval.d.ts +27 -1
- package/dist/types.d.ts +0 -41
- package/package.json +5 -4
- package/dist/constants.d.ts +0 -4
- package/dist/enableFeatures.d.ts +0 -6
- package/dist/registerComponents.d.ts +0 -7
- package/dist/utils.d.ts +0 -40
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
This plugin introduces background removal for the CE.SDK editor, leveraging the power of the [background-removal-js library](https://github.com/imgly/background-removal-js). It integrates seamlessly with CE.SDK,
|
|
5
|
+
This plugin introduces background removal for the CE.SDK editor, leveraging the power of the [background-removal-js library](https://github.com/imgly/background-removal-js). It integrates seamlessly with CE.SDK, provides users with an efficient tool to remove backgrounds from images directly in the browser with ease and no additional costs or privacy concerns.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -23,28 +23,29 @@ import CreativeEditorSDK from '@cesdk/cesdk-js';
|
|
|
23
23
|
import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web';
|
|
24
24
|
|
|
25
25
|
const config = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
license: '<your-license-here>',
|
|
27
|
+
callbacks: {
|
|
28
|
+
// Please note that the background removal plugin depends on an correctly
|
|
29
|
+
// configured upload. 'local' will work for local testing, but in
|
|
30
|
+
// production you will need something stable. Please take a look at:
|
|
31
|
+
// https://img.ly/docs/cesdk/ui/guides/upload-images/
|
|
32
|
+
onUpload: 'local'
|
|
33
|
+
}
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
const cesdk = await CreativeEditorSDK.create(container, config);
|
|
37
37
|
await cesdk.addDefaultAssetSources(),
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
await cesdk.addDemoAssetSources({ sceneMode: 'Design' }),
|
|
39
|
+
await cesdk.unstable_addPlugin(BackgroundRemovalPlugin());
|
|
40
40
|
|
|
41
41
|
await cesdk.createDesignScene();
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
## Configuration
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
By default, this plugin uses the `@imgly/background-removal-js` library to remove
|
|
47
|
+
a background from the image fill. All configuration options from this underlying
|
|
48
|
+
library can be used in this plugin.
|
|
48
49
|
|
|
49
50
|
[See the documentation](https://github.com/imgly/background-removal-js/tree/main/packages/web#advanced-configuration) for further information.
|
|
50
51
|
|
|
@@ -54,10 +55,13 @@ import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web';
|
|
|
54
55
|
[...]
|
|
55
56
|
|
|
56
57
|
await cesdk.unstable_addPlugin(BackgroundRemovalPlugin({
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
provider: {
|
|
59
|
+
type: '@imgly/background-removal',
|
|
60
|
+
configuration: {
|
|
61
|
+
publicPath: '...',
|
|
62
|
+
// All other configuration options that are passed to the bg removal
|
|
63
|
+
// library. See https://github.com/imgly/background-removal-js/tree/main/packages/web#advanced-configuration
|
|
64
|
+
}
|
|
61
65
|
}
|
|
62
66
|
}))
|
|
63
67
|
|
|
@@ -71,3 +75,83 @@ For optimal performance using the correct CORS headers is important. See the lib
|
|
|
71
75
|
'Cross-Origin-Opener-Policy': 'same-origin',
|
|
72
76
|
'Cross-Origin-Embedder-Policy': 'require-corp'
|
|
73
77
|
```
|
|
78
|
+
|
|
79
|
+
## Custom Background Removal Provider
|
|
80
|
+
|
|
81
|
+
It is possible to declare a different provider for the background removal process.
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
BackgroundRemovalPlugin({
|
|
85
|
+
provider: {
|
|
86
|
+
type: 'custom',
|
|
87
|
+
// If the image has only one image file URI defined, this method will
|
|
88
|
+
// be called. It must return a single new image file URI with the
|
|
89
|
+
// removed background.
|
|
90
|
+
processImageFileURI: async (imageFileURI: string) => {
|
|
91
|
+
const blob = await removeBackground(imageFileURI);
|
|
92
|
+
const upload = await uploadBlob(blob);
|
|
93
|
+
return upload;
|
|
94
|
+
},
|
|
95
|
+
// Some images have a source set defined which provides multiple images
|
|
96
|
+
// in different sizes.
|
|
97
|
+
processSourceSet: async (
|
|
98
|
+
// Source set for the current block sorted by the resolution.
|
|
99
|
+
// URI with the highest URI is first
|
|
100
|
+
sourceSet: {
|
|
101
|
+
uri: string;
|
|
102
|
+
width: number;
|
|
103
|
+
height: number;
|
|
104
|
+
}[],
|
|
105
|
+
) => {
|
|
106
|
+
// You should call the remove background method on every URI in the
|
|
107
|
+
// source set. Depending on your service or your algorithm, you
|
|
108
|
+
// have the following options:
|
|
109
|
+
// - Return a source set with a single image (will contradict the use-case of source sets and degrades the user experience)
|
|
110
|
+
// - Create a segmented mask and apply it to every image (not always available)
|
|
111
|
+
// - Create a new source set by resizing the resulting blob.
|
|
112
|
+
|
|
113
|
+
// In this example we will do the last case.
|
|
114
|
+
// First image has the highest resolution and might be the best
|
|
115
|
+
// candidate to remove the background.
|
|
116
|
+
const highestResolution = sourceSet[0];
|
|
117
|
+
const highestResolutionBlob = await removeBackground(highestResolution.uri);
|
|
118
|
+
const highestResolutionURI = await uploadBlob(highestResolutionBlob);
|
|
119
|
+
|
|
120
|
+
const remainingSources = await Promise.all(
|
|
121
|
+
sourceSet.slice(1).map((source) => {
|
|
122
|
+
// ...
|
|
123
|
+
const upload = uploadBlob(/* ... */)
|
|
124
|
+
return { ...source, uri: upload };
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
return [{ ...highestResolution, uri: highestResolutionURI }, remainingSources];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Depending on your use case or service you might end up with a blob that you want to upload by the
|
|
135
|
+
configured upload handler of the editor. This might look like the following function:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
async function uploadBlob(
|
|
139
|
+
blob: Blob,
|
|
140
|
+
initialUri: string,
|
|
141
|
+
cesdk: CreativeEditorSDK
|
|
142
|
+
) {
|
|
143
|
+
const pathname = new URL(initialUri).pathname;
|
|
144
|
+
const parts = pathname.split('/');
|
|
145
|
+
const filename = parts[parts.length - 1];
|
|
146
|
+
|
|
147
|
+
const uploadedAssets = await cesdk.unstable_upload(
|
|
148
|
+
new File([blob], filename, { type: blob.type })
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const url = uploadedAssets.meta?.uri;
|
|
152
|
+
if (url == null) {
|
|
153
|
+
throw new Error('Could not upload processed fill');
|
|
154
|
+
}
|
|
155
|
+
return url;
|
|
156
|
+
}
|
|
157
|
+
```
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import p from"lodash/isEqual";var w=class{constructor(e,i){this.cesdk=e,this.key=i}hasData(e){return this.cesdk.engine.block.isValid(e)&&this.cesdk.engine.block.hasMetadata(e,this.key)}get(e){if(this.hasData(e))return JSON.parse(this.cesdk.engine.block.getMetadata(e,this.key))}set(e,i){this.cesdk.engine.block.setMetadata(e,this.key,JSON.stringify(i))}clear(e){this.cesdk.engine.block.hasMetadata(e,this.key)&&this.cesdk.engine.block.removeMetadata(e,this.key)}},D=w,U=class extends D{get(e){return super.get(e)??{status:"IDLE"}}isDuplicate(e){if(!this.cesdk.engine.block.isValid(e))return!1;let i=this.get(e);if(i.status==="IDLE"||i.status==="PENDING"||i.status==="ERROR"||!this.cesdk.engine.block.hasFill(e))return!1;let t=this.cesdk.engine.block.getFill(e);return!(i.blockId===e||i.fillId===t)}fixDuplicate(e){let i=this.cesdk.engine.block.getFill(e),t=this.get(e);t.status==="IDLE"||t.status==="PENDING"||t.status==="ERROR"||(this.set(e,{...t,blockId:e,fillId:i}),t.status==="PROCESSING"&&(this.recoverInitialImageData(e),this.clear(e)))}isConsistent(e){if(!this.cesdk.engine.block.isValid(e))return!1;let i=this.get(e);if(i.status==="IDLE"||i.status==="PENDING")return!0;if(!this.cesdk.engine.block.hasFill(e))return!1;let t=this.cesdk.engine.block.getFill(e);if(t==null||e!==i.blockId||t!==i.fillId)return!1;let a=this.cesdk.engine.block.getSourceSet(t,"fill/image/sourceSet"),l=this.cesdk.engine.block.getString(t,"fill/image/imageFileURI");if(a.length===0&&!l&&i.status==="PROCESSING")return!0;if(a?.length>0){let s=i.initialSourceSet;if(i.status==="PROCESSED"){if(!p(a,i.processed)&&!p(a,s))return!1}else if(!p(a,s))return!1}else if(i.status==="PROCESSED"){if(l!==i.initialImageFileURI&&l!==i.processed)return!1}else if(l!==i.initialImageFileURI)return!1;return!0}recoverInitialImageData(e){if(!this.cesdk.engine.block.hasFill(e))return;let i=this.get(e);if(i.status==="PENDING"||i.status==="IDLE")return;let t=i.initialSourceSet,a=i.initialImageFileURI,l=i.initialPreviewFileURI,s=this.getValidFill(e,i);s!=null&&(a&&this.cesdk.engine.block.setString(s,"fill/image/imageFileURI",a),l&&this.cesdk.engine.block.setString(s,"fill/image/previewFileURI",l),t.length>0&&this.cesdk.engine.block.setSourceSet(s,"fill/image/sourceSet",t))}getValidFill(e,i){if(!this.cesdk.engine.block.isValid(e)||!this.cesdk.engine.block.hasFill(e)||e!==i.blockId)return;let t=this.cesdk.engine.block.getFill(e);if(t===i.fillId)return t}},I=U;async function S(e,i,t,a,l){let s=e.engine.block;if(!s.hasFill(i))throw new Error("Block has no fill to process");let n=s.getFill(i),r=s.getSourceSet(n,"fill/image/sourceSet"),u=s.getString(n,"fill/image/imageFileURI"),d=s.getString(n,"fill/image/previewFileURI");try{s.setString(n,"fill/image/imageFileURI",""),s.setSourceSet(n,"fill/image/sourceSet",[]),t.set(i,{...t.get(i),version:"0.0.0",initialSourceSet:r,initialImageFileURI:u,initialPreviewFileURI:d,blockId:i,fillId:n,status:"PROCESSING"});let o=r.sort((c,f)=>f.width*f.height-c.height*c.width),g=r.length>0?o[0].uri:u;if(d||s.setString(n,"fill/image/previewFileURI",g),r.length>0){let c=await a(r);if(t.get(i).status!=="PROCESSING"||!t.isConsistent(i)||t.get(i).status!=="PROCESSING"||!t.isConsistent(i)||c==null)return;if(c.every(f=>f==null))throw new Error("Empty source set after processing fill");t.set(i,{version:"0.0.0",initialSourceSet:r,initialImageFileURI:u,initialPreviewFileURI:d,blockId:i,fillId:n,status:"PROCESSED",processed:c}),s.setSourceSet(n,"fill/image/sourceSet",c),s.setString(n,"fill/image/previewFileURI","")}else{let c=await l(g);if(t.get(i).status!=="PROCESSING"||!t.isConsistent(i)||t.get(i).status!=="PROCESSING"||!t.isConsistent(i))return;if(c==null)throw new Error("Could not upload fill processed data");t.set(i,{version:"0.0.0",initialSourceSet:r,initialImageFileURI:u,initialPreviewFileURI:d,blockId:i,fillId:n,status:"PROCESSED",processed:c}),s.setString(n,"fill/image/imageFileURI",c),s.setString(n,"fill/image/previewFileURI","")}e.engine.editor.addUndoStep()}catch(o){e.engine.block.isValid(i)&&(t.set(i,{version:"0.0.0",initialSourceSet:r,initialImageFileURI:u,initialPreviewFileURI:d,blockId:i,fillId:n,status:"ERROR"}),t.recoverInitialImageData(i)),o!=null&&typeof o=="object"&&"message"in o&&typeof o.message=="string"&&e.ui.showNotification({type:"error",message:o.message}),console.log(o)}}function h(e){return`${e}.fillProcessing.feature`}function N(e){return`${e}.fillProcessing.canvasMenu`}function O(e){return`plugin.${e}.fillProcessing.canvasMenu.button.label`}function b(e,{pluginId:i,process:t}){let a=h(i),l=new I(e,i);return G(e,l,a),e.engine.event.subscribe([],async s=>{s.forEach(n=>{let r=n.block;if(!(!e.engine.block.isValid(r)||!l.hasData(r))){if(n.type==="Created")l.isDuplicate(r)&&l.fixDuplicate(r);else if(n.type==="Updated")switch(l.get(r).status){case"PENDING":{e.feature.unstable_isEnabled(a,{engine:e.engine})&&e.engine.block.isAllowedByScope(r,"fill/change")&&t(r,l);break}case"PROCESSING":case"PROCESSED":{l.isConsistent(r)||l.clear(r);break}default:}}})}),{featureId:a}}function G(e,i,t){e.feature.unstable_enable(t,({engine:a})=>{let l=a.block.findAllSelected();if(l.length!==1)return!1;let[s]=l;if(!e.engine.block.isVisible(s))return!1;if(e.engine.block.hasFill(s)){if(e.engine.block.getKind(s)==="sticker")return!1;let n=e.engine.block.getFill(s);if(e.engine.block.getType(n)!=="//ly.img.ubq/fill/image")return!1;let r=a.block.getString(n,"fill/image/imageFileURI");return a.block.getSourceSet(n,"fill/image/sourceSet").length>0||r!==""?!0:i.get(s).status==="PROCESSING"}return!1})}function R(e,i){let{pluginId:t,locations:a}=i,l=new I(e,t),s=N(t),n=O(t),r=h(t);return a?.includes("canvasMenu")&&e.ui.unstable_setCanvasMenuOrder([s,...e.ui.unstable_getCanvasMenuOrder()]),e.ui.unstable_registerComponent(s,({builder:{Button:u},engine:d})=>{if(!e.feature.unstable_isEnabled(r,{engine:d}))return;let[o]=d.block.findAllSelected();if(!e.engine.block.isAllowedByScope(o,"fill/change"))return;let g=l.get(o),c=g.status==="PROCESSING",f=g.status==="PENDING"||g.status==="PROCESSING",k;if(c&&g.progress){let{current:F,total:y}=g.progress;k=F/y*100}let C=`${s}.button`;u(C,{label:n,icon:i.icon,isLoading:c,isDisabled:f,loadingProgress:k,onClick:()=>{(g.status==="IDLE"||g.status==="ERROR"||g.status==="PROCESSED")&&l.set(o,{status:"PENDING"})}})}),{canvasMenuComponentId:s,translationsKeys:{canvasMenuLabel:n}}}import{applySegmentationMask as M,removeBackground as B,segmentForeground as L}from"@imgly/background-removal";import x from"lodash/throttle";async function P(e,i,t,a){switch(a.type){case"@imgly/background-removal":{let l=a.configuration??{},s={device:"gpu",...l,progress:x((n,r,u)=>{let d=t.get(i);d.status!=="PROCESSING"||!t.isConsistent(i)||(l.progress?.(n,r,u),t.set(i,{...d,progress:{key:n,current:r,total:u}}))},100)};S(e,i,t,async n=>{let r=n[0].uri,u=await L(r,l);return await Promise.all(n.map(async o=>{let g=await M(o.uri,u,s),c=await v(g,o.uri,e);return{...o,uri:c}}))},async n=>{let r=await B(n,s);return await v(r,n,e)});break}case"custom":{S(e,i,t,a.processSourceSet,a.processImageFileURI);break}default:throw new Error("Unknown background removal provider")}}async function v(e,i,t){let l=new URL(i).pathname.split("/"),s=l[l.length-1],r=(await t.unstable_upload(new File([e],s,{type:e.type}),()=>{})).meta?.uri;if(r==null)throw new Error("Could not upload processed fill");return r}var m="@imgly/plugin-background-removal-web",E=(e={})=>({initialize(){},update(){},initializeUserInterface({cesdk:i}){b(i,{pluginId:m,process:(a,l)=>{P(i,a,l,e.provider??{type:"@imgly/background-removal"})}});let{translationsKeys:t}=R(i,{pluginId:m,icon:"@imgly/icons/BGRemove",locations:e.ui?.locations});i.setTranslations({en:{[t.canvasMenuLabel]:"BG Removal"}})}});var V=e=>({name:m,version:"0.3.0-rc.0",...E(e)}),W=V;export{W as default};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["
|
|
4
|
-
"sourcesContent": ["export const PLUGIN_ID = '@imgly/plugin-background-removal-web';\nexport const CANVAS_MENU_COMPONENT_ID = `${PLUGIN_ID}.canvasMenu`;\nexport const CANVAS_MENU_COMPONENT_BUTTON_ID = `${CANVAS_MENU_COMPONENT_ID}.button`;\nexport const FEATURE_ID = `${PLUGIN_ID}.feature`;\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\nimport isEqual from 'lodash/isEqual';\n\nimport { PLUGIN_ID } from './constants';\nimport {\n PluginStatusError,\n PluginStatusMetadata,\n PluginStatusProcessed,\n PluginStatusProcessing\n} from './types';\n\n/**\n * Sets the metadata for the plugin state.\n */\nexport function setPluginMetadata(\n cesdk: CreativeEditorSDK,\n id: number,\n metadata: PluginStatusMetadata\n) {\n cesdk.engine.block.setMetadata(id, PLUGIN_ID, JSON.stringify(metadata));\n}\n\n/**\n * Returns the current metadata for the plugin state. If no metadata\n * is set on the given block, it will return an IDLE state.\n */\nexport function getPluginMetadata(\n cesdk: CreativeEditorSDK,\n id: number\n): PluginStatusMetadata {\n if (cesdk.engine.block.hasMetadata(id, PLUGIN_ID)) {\n return JSON.parse(cesdk.engine.block.getMetadata(id, PLUGIN_ID));\n } else {\n return {\n status: 'IDLE'\n };\n }\n}\n\n/**\n * If plugin metadata is set, it will be cleared.\n */\nexport function clearPluginMetadata(cesdk: CreativeEditorSDK, id: number) {\n if (cesdk.engine.block.hasMetadata(id, PLUGIN_ID)) {\n cesdk.engine.block.removeMetadata(id, PLUGIN_ID);\n }\n}\n\n/**\n * Detect if the block has been duplicated with processed or processing\n * background removal. In that case the background removal state is still\n * valid, but blockId and fillId have changed.\n */\nexport function isDuplicate(\n cesdk: CreativeEditorSDK,\n blockId: number,\n metadata: PluginStatusMetadata\n): boolean {\n if (!cesdk.engine.block.isValid(blockId)) return false;\n if (\n metadata.status === 'IDLE' ||\n metadata.status === 'PENDING' ||\n metadata.status === 'ERROR'\n )\n return false;\n\n if (!cesdk.engine.block.hasFill(blockId)) return false;\n const fillId = cesdk.engine.block.getFill(blockId);\n\n // It cannot be a duplicate if the blockId or fillId are the same\n if (metadata.blockId === blockId || metadata.fillId === fillId) return false;\n\n return true;\n}\n\n/**\n * Fixes the metadata if the block has been duplicated, i.e. the blockId and\n * fillId will be updated to the current block/fill.\n *\n * Please note: Call this method only on duplicates (see isDuplicate).\n */\nexport function fixDuplicateMetadata(\n cesdk: CreativeEditorSDK,\n blockId: number\n) {\n const fillId = cesdk.engine.block.getFill(blockId);\n const metadata = getPluginMetadata(cesdk, blockId);\n if (\n metadata.status === 'IDLE' ||\n metadata.status === 'PENDING' ||\n metadata.status === 'ERROR'\n )\n return;\n setPluginMetadata(cesdk, blockId, {\n ...metadata,\n blockId,\n fillId\n });\n}\n\n/**\n * Check if the image has a consisten metadata state. A inconsistent state is\n * caused by outside changes of the fill data.\n *\n * @returns true if the metadata is consistent, false otherwise\n */\nexport function isMetadataConsistent(\n cesdk: CreativeEditorSDK,\n blockId: number\n): boolean {\n // In case the block was removed, we just abort and mark it\n // as reset by returning true\n if (!cesdk.engine.block.isValid(blockId)) return false;\n const metadata = getPluginMetadata(cesdk, blockId);\n if (metadata.status === 'IDLE' || metadata.status === 'PENDING') return true;\n\n if (!cesdk.engine.block.hasFill(blockId)) return false;\n const fillId = cesdk.engine.block.getFill(blockId);\n if (fillId == null) return false;\n\n if (blockId !== metadata.blockId || fillId !== metadata.fillId) return false;\n\n const sourceSet = cesdk.engine.block.getSourceSet(\n fillId,\n 'fill/image/sourceSet'\n );\n const imageFileURI = cesdk.engine.block.getString(\n fillId,\n 'fill/image/imageFileURI'\n );\n\n if (\n sourceSet.length === 0 &&\n !imageFileURI &&\n metadata.status === 'PROCESSING'\n ) {\n // While we process it is OK to have no image file URI and no source set\n // (which we cleared to show the spinning loader)\n return true;\n }\n\n // Source sets have precedence over imageFileURI so if we have a source set,\n // we only need to check if it has changed to something else.\n if (sourceSet?.length > 0) {\n const initialSourceSet = metadata.initialSourceSet;\n // If we have already processed the image, we need to check if the source set\n // we need to check against both source sets, the removed and the initial\n if (metadata.status === 'PROCESSED') {\n const removedBackground = metadata.removedBackground;\n if (\n !isEqual(sourceSet, removedBackground) &&\n !isEqual(sourceSet, initialSourceSet)\n ) {\n return false;\n }\n } else {\n if (!isEqual(sourceSet, initialSourceSet)) {\n return false;\n }\n }\n } else {\n if (metadata.status === 'PROCESSED') {\n if (\n imageFileURI !== metadata.initialImageFileURI &&\n imageFileURI !== metadata.removedBackground\n ) {\n return false;\n }\n } else {\n if (imageFileURI !== metadata.initialImageFileURI) {\n return false;\n }\n }\n }\n return true;\n}\n\n/**\n * Recover the initial values to avoid the loading spinner and have the same\n * state as before the background removal was started.\n */\nexport function recoverInitialImageData(\n cesdk: CreativeEditorSDK,\n blockId: number\n) {\n const blockApi = cesdk.engine.block;\n if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore)\n\n const metadata = getPluginMetadata(cesdk, blockId);\n\n if (metadata.status === 'PENDING' || metadata.status === 'IDLE') {\n return;\n }\n\n const initialSourceSet = metadata.initialSourceSet;\n const initialImageFileURI = metadata.initialImageFileURI;\n const initialPreviewFileURI = metadata.initialPreviewFileURI;\n\n const fillId = getValidFill(cesdk, blockId, metadata);\n if (fillId == null) return;\n\n if (initialImageFileURI) {\n cesdk.engine.block.setString(\n fillId,\n 'fill/image/imageFileURI',\n initialImageFileURI\n );\n }\n if (initialPreviewFileURI) {\n cesdk.engine.block.setString(\n fillId,\n 'fill/image/previewFileURI',\n initialPreviewFileURI\n );\n }\n if (initialSourceSet.length > 0) {\n cesdk.engine.block.setSourceSet(\n fillId,\n 'fill/image/sourceSet',\n initialSourceSet\n );\n }\n}\n\n/**\n * Returns the fill id of the block if it has a valid fill that was used for\n * background removal. Returns undefined otherwise.\n */\nfunction getValidFill(\n cesdk: CreativeEditorSDK,\n blockId: number,\n metadata: PluginStatusProcessing | PluginStatusError | PluginStatusProcessed\n): number | undefined {\n if (\n !cesdk.engine.block.isValid(blockId) ||\n !cesdk.engine.block.hasFill(blockId) ||\n blockId !== metadata.blockId\n ) {\n return undefined;\n }\n const fillId = cesdk.engine.block.getFill(blockId);\n if (fillId !== metadata.fillId) {\n return undefined;\n }\n\n return fillId;\n}\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\nimport { FEATURE_ID } from './constants';\nimport { getPluginMetadata } from './utils';\n\n/**\n * Defines the feature that determines in which context (on which block)\n * background removal is allowed/enabled.\n */\nexport function enableFeatures(cesdk: CreativeEditorSDK) {\n cesdk.feature.unstable_enable(FEATURE_ID, ({ engine }) => {\n const selectedIds = engine.block.findAllSelected();\n if (selectedIds.length !== 1) {\n return false;\n }\n const [selectedId] = selectedIds;\n\n if (cesdk.engine.block.hasFill(selectedId)) {\n const fillId = cesdk.engine.block.getFill(selectedId);\n const fillType = cesdk.engine.block.getType(fillId);\n\n if (fillType !== '//ly.img.ubq/fill/image') {\n return false;\n }\n\n const fileUri = engine.block.getString(fillId, 'fill/image/imageFileURI');\n const sourceSet = engine.block.getSourceSet(\n fillId,\n 'fill/image/sourceSet'\n );\n\n if (sourceSet.length > 0 || fileUri !== '') return true;\n\n // If we are in a processing state we do not have a imageFileURI or\n // source set set (to show the loading spinner), but the feature is still\n // enabled.\n const metadata = getPluginMetadata(cesdk, selectedId);\n return metadata.status === 'PROCESSING';\n }\n\n return false;\n });\n}\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\nimport { type Source } from '@cesdk/cesdk-js';\nimport {\n applySegmentationMask,\n segmentForeground,\n type Config\n} from '@imgly/background-removal';\n\nimport throttle from 'lodash/throttle';\n\nimport {\n getPluginMetadata,\n isMetadataConsistent,\n recoverInitialImageData,\n setPluginMetadata\n} from './utils';\n\n/**\n * Triggers the background removal process.\n */\nexport async function processBackgroundRemoval(\n cesdk: CreativeEditorSDK,\n blockId: number,\n configuration: Config\n) {\n const blockApi = cesdk.engine.block;\n if (!blockApi.hasFill(blockId))\n throw new Error('Block has no fill to remove the background from');\n\n const fillId = blockApi.getFill(blockId);\n\n // Get the current image URI and source set as initial values.\n const initialSourceSet = blockApi.getSourceSet(\n fillId,\n 'fill/image/sourceSet'\n );\n const initialImageFileURI = blockApi.getString(\n fillId,\n 'fill/image/imageFileURI'\n );\n const initialPreviewFileURI = blockApi.getString(\n fillId,\n 'fill/image/previewFileURI'\n );\n\n try {\n // Clear values in the engine to trigger the loading spinner\n blockApi.setString(fillId, 'fill/image/imageFileURI', '');\n blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []);\n\n const metadata = getPluginMetadata(cesdk, blockId);\n setPluginMetadata(cesdk, blockId, {\n ...metadata,\n version: PLUGIN_VERSION,\n initialSourceSet,\n initialImageFileURI,\n initialPreviewFileURI,\n blockId,\n fillId,\n status: 'PROCESSING'\n });\n\n const uriToProcess =\n // Source sets have priority in the engine\n initialSourceSet.length > 0\n ? // Choose the highest resolution image in the source set\n initialSourceSet.sort(\n (a, b) => b.width * b.height - a.height * a.width\n )[0].uri\n : initialImageFileURI;\n\n // If there is no initial preview file URI, set the current URI.\n // It will be used as the image displayed while showing the loading spinner.\n if (!initialPreviewFileURI) {\n blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess);\n }\n\n // Creating the mask from the highest resolution image\n const mask = await segmentForeground(uriToProcess, configuration);\n\n if (initialSourceSet.length > 0) {\n // Source set code path\n // ====================\n const uploaded = await maskSourceSet<Source>(\n cesdk,\n blockId,\n initialSourceSet,\n mask,\n configuration\n );\n if (uploaded == null) return;\n\n if (uploaded.every((url) => url == null)) {\n throw new Error('Could not upload any BG removed image');\n }\n\n const newSourceSet = initialSourceSet.map((source, index) => {\n return {\n ...source,\n uri: uploaded[index]\n };\n });\n\n setPluginMetadata(cesdk, blockId, {\n version: PLUGIN_VERSION,\n initialSourceSet,\n initialImageFileURI,\n initialPreviewFileURI,\n blockId,\n fillId,\n status: 'PROCESSED',\n removedBackground: newSourceSet\n });\n blockApi.setSourceSet(fillId, 'fill/image/sourceSet', newSourceSet);\n // TODO: Generate a thumb/preview uri\n blockApi.setString(fillId, 'fill/image/previewFileURI', '');\n } else {\n // ImageFileURI code path\n // ======================\n const uploaded = await maskSourceSet<{ uri: string }>(\n cesdk,\n blockId,\n [{ uri: uriToProcess }],\n mask,\n configuration\n );\n if (uploaded == null) return;\n\n const uploadedUrl = uploaded[0];\n if (uploadedUrl == null) {\n throw new Error('Could not upload BG removed image');\n }\n\n setPluginMetadata(cesdk, blockId, {\n version: PLUGIN_VERSION,\n initialSourceSet,\n initialImageFileURI,\n initialPreviewFileURI,\n blockId,\n fillId,\n status: 'PROCESSED',\n removedBackground: uploadedUrl\n });\n blockApi.setString(fillId, 'fill/image/imageFileURI', uploadedUrl);\n // TODO: Generate a thumb/preview uri\n blockApi.setString(fillId, 'fill/image/previewFileURI', '');\n }\n // Finally, create an undo step\n cesdk.engine.editor.addUndoStep();\n } catch (error) {\n if (cesdk.engine.block.isValid(blockId)) {\n setPluginMetadata(cesdk, blockId, {\n version: PLUGIN_VERSION,\n initialSourceSet,\n initialImageFileURI,\n initialPreviewFileURI,\n blockId,\n fillId,\n status: 'ERROR'\n });\n\n recoverInitialImageData(cesdk, blockId);\n }\n // eslint-disable-next-line no-console\n console.log(error);\n }\n}\n\nasync function maskSourceSet<T extends { uri: string }>(\n cesdk: CreativeEditorSDK,\n blockId: number,\n urisOrSources: T[],\n mask: Blob,\n configurationFromArgs: Config\n): Promise<string[] | undefined> {\n const configuration = {\n ...configurationFromArgs,\n progress: throttle((key, current, total) => {\n const metadataDuringProgress = getPluginMetadata(cesdk, blockId);\n if (\n metadataDuringProgress.status !== 'PROCESSING' ||\n !isMetadataConsistent(cesdk, blockId)\n )\n return;\n configurationFromArgs.progress?.(key, current, total);\n setPluginMetadata(cesdk, blockId, {\n ...metadataDuringProgress,\n progress: { key, current, total }\n });\n }, 100)\n };\n\n const masked = await Promise.all(\n urisOrSources.map(async (source): Promise<[Blob, T]> => {\n // Applying the mask to the original image\n const blob = await applySegmentationMask(source.uri, mask, configuration);\n return [blob, source];\n })\n );\n\n // Check for externally changed state while we were applying the mask and\n // do not proceed if the state was reset.\n if (\n getPluginMetadata(cesdk, blockId).status !== 'PROCESSING' ||\n !isMetadataConsistent(cesdk, blockId)\n )\n return;\n\n const uploaded = await Promise.all(\n masked.map(async ([blob, source]): Promise<[string, T]> => {\n const pathname = new URL(source.uri).pathname;\n const parts = pathname.split('/');\n const filename = parts[parts.length - 1];\n\n const uploadedAssets = await cesdk.unstable_upload(\n new File([blob], filename, { type: blob.type }),\n () => {\n // TODO Delegate process to UI component\n }\n );\n\n const url = uploadedAssets.meta?.uri;\n if (url == null) {\n throw new Error('Could not upload BG removed image');\n }\n return [url, source];\n })\n );\n\n // Check for externally changed state while we were uploading and\n // do not proceed if the state was reset.\n if (\n getPluginMetadata(cesdk, blockId).status !== 'PROCESSING' ||\n !isMetadataConsistent(cesdk, blockId)\n )\n return;\n\n return uploaded.map(([url]) => url);\n}\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\n\nimport {\n CANVAS_MENU_COMPONENT_BUTTON_ID,\n CANVAS_MENU_COMPONENT_ID,\n FEATURE_ID,\n PLUGIN_ID\n} from './constants';\nimport { Location, UserInterfaceConfiguration } from './types';\nimport { getPluginMetadata, setPluginMetadata } from './utils';\n\nconst REMOVE_BACKGROUND_ACTION_I18N_KEY = `plugin.${PLUGIN_ID}.action.removeBackground`;\n\n/**\n * Registers the components that can be used to remove the background of\n * a block.\n */\nexport function registerComponents(\n cesdk: CreativeEditorSDK,\n configuration: UserInterfaceConfiguration = {}\n) {\n if (hasDefaultLocation('canvasMenu', configuration)) {\n // Always prepend the registered component to the canvas menu order.\n cesdk.ui.unstable_setCanvasMenuOrder([\n CANVAS_MENU_COMPONENT_ID,\n ...cesdk.ui.unstable_getCanvasMenuOrder()\n ]);\n }\n\n cesdk.setTranslations({\n en: {\n [REMOVE_BACKGROUND_ACTION_I18N_KEY]: 'BG Removal'\n }\n });\n\n cesdk.ui.unstable_registerComponent(\n CANVAS_MENU_COMPONENT_ID,\n ({ builder: { Button }, engine }) => {\n if (\n !cesdk.feature.unstable_isEnabled(FEATURE_ID, {\n engine\n })\n ) {\n return;\n }\n\n const [id] = engine.block.findAllSelected();\n\n const metadata = getPluginMetadata(cesdk, id);\n\n const isLoading = metadata.status === 'PROCESSING';\n const isDisabled =\n metadata.status === 'PENDING' || metadata.status === 'PROCESSING';\n\n let loadingProgress: number | undefined;\n if (isLoading && metadata.progress) {\n const { key, current, total } = metadata.progress;\n\n if (key === 'compute:inference') {\n loadingProgress = undefined;\n } else if (key.startsWith('fetch:/models/')) {\n loadingProgress = (current / total) * 50;\n } else if (key.startsWith('fetch:/onnxruntime-web/')) {\n loadingProgress = 50 + (current / total) * 50;\n } else {\n loadingProgress = undefined;\n }\n }\n\n Button(CANVAS_MENU_COMPONENT_BUTTON_ID, {\n label: REMOVE_BACKGROUND_ACTION_I18N_KEY,\n icon: '@imgly/icons/BGRemove',\n isLoading,\n isDisabled,\n loadingProgress,\n onClick: () => {\n if (\n metadata.status === 'IDLE' ||\n metadata.status === 'ERROR' ||\n metadata.status === 'PROCESSED'\n ) {\n setPluginMetadata(cesdk, id, {\n status: 'PENDING'\n });\n }\n }\n });\n }\n );\n}\n\nfunction hasDefaultLocation(\n location: Location,\n configuration: UserInterfaceConfiguration\n) {\n return (\n configuration.locations &&\n (Array.isArray(configuration.locations)\n ? configuration.locations\n : [configuration.locations]\n ).includes(location)\n );\n}\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\n\nimport type { Config as BackgroundRemovalConfiguration } from '@imgly/background-removal';\nimport { FEATURE_ID, PLUGIN_ID } from './constants';\nimport { enableFeatures } from './enableFeatures';\nimport { processBackgroundRemoval } from './processBackgroundRemoval';\nimport { registerComponents } from './registerComponents';\nimport { UserInterfaceConfiguration } from './types';\nimport {\n clearPluginMetadata,\n fixDuplicateMetadata,\n getPluginMetadata,\n isDuplicate,\n isMetadataConsistent\n} from './utils';\n\nexport interface PluginConfiguration {\n ui?: UserInterfaceConfiguration;\n backgroundRemoval?: BackgroundRemovalConfiguration;\n}\n\nexport default (pluginConfiguration: PluginConfiguration = {}) => {\n const backgroundRemovalConfiguration: BackgroundRemovalConfiguration =\n pluginConfiguration?.backgroundRemoval ?? {};\n\n return {\n initialize() {},\n\n update() {},\n\n initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) {\n cesdk.engine.event.subscribe([], async (events) => {\n events.forEach((e) => {\n const id = e.block;\n if (\n !cesdk.engine.block.isValid(id) ||\n !cesdk.engine.block.hasMetadata(id, PLUGIN_ID)\n ) {\n return;\n }\n\n if (e.type === 'Created') {\n const metadata = getPluginMetadata(cesdk, id);\n if (isDuplicate(cesdk, id, metadata)) {\n fixDuplicateMetadata(cesdk, id);\n }\n } else if (e.type === 'Updated') {\n handleUpdateEvent(cesdk, id, backgroundRemovalConfiguration);\n }\n });\n });\n\n registerComponents(cesdk, pluginConfiguration.ui);\n enableFeatures(cesdk);\n }\n };\n};\n\n/**\n * Handle every possible state of the background removal state if the block was\n * updated.\n */\nasync function handleUpdateEvent(\n cesdk: CreativeEditorSDK,\n blockId: number,\n configuration: BackgroundRemovalConfiguration\n) {\n const metadata = getPluginMetadata(cesdk, blockId);\n\n switch (metadata.status) {\n case 'PENDING': {\n if (\n cesdk.feature.unstable_isEnabled(FEATURE_ID, {\n engine: cesdk.engine\n })\n ) {\n processBackgroundRemoval(cesdk, blockId, configuration);\n }\n break;\n }\n\n case 'PROCESSING':\n case 'PROCESSED': {\n if (!isMetadataConsistent(cesdk, blockId)) {\n clearPluginMetadata(cesdk, blockId);\n }\n break;\n }\n\n default: {\n // We do not care about other states\n }\n }\n}\n", "import plugin, { type PluginConfiguration } from './plugin';\n\nimport { PLUGIN_ID } from './constants';\n\nconst Plugin = (pluginConfiguration?: PluginConfiguration) => ({\n name: PLUGIN_ID,\n version: PLUGIN_VERSION,\n ...plugin(pluginConfiguration)\n});\n\nexport default Plugin;\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["
|
|
3
|
+
"sources": ["../../plugin-utils/src/metadata/Metadata.ts", "../../plugin-utils/src/metadata/FillProcessingMetadata.ts", "../../plugin-utils/src/processing/processFill.ts", "../../plugin-utils/src/processing/constants.ts", "../../plugin-utils/src/processing/initializeFillProcessing.ts", "../../plugin-utils/src/processing/registerFillProcessingComponents.ts", "../src/processBackgroundRemoval.ts", "../src/plugin.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type CreativeEditorSDK from '@cesdk/cesdk-js';\n\nclass Metadata<V> {\n cesdk: CreativeEditorSDK;\n\n key: string;\n\n constructor(cesdk: CreativeEditorSDK, key: string) {\n this.cesdk = cesdk;\n this.key = key;\n }\n\n hasData(blockId: number): boolean {\n return (\n this.cesdk.engine.block.isValid(blockId) &&\n this.cesdk.engine.block.hasMetadata(blockId, this.key)\n );\n }\n\n get(blockId: number): V | undefined {\n if (this.hasData(blockId)) {\n return JSON.parse(this.cesdk.engine.block.getMetadata(blockId, this.key));\n }\n return undefined;\n }\n\n set(blockId: number, value: V) {\n this.cesdk.engine.block.setMetadata(\n blockId,\n this.key,\n JSON.stringify(value)\n );\n }\n\n clear(blockId: number) {\n if (this.cesdk.engine.block.hasMetadata(blockId, this.key)) {\n this.cesdk.engine.block.removeMetadata(blockId, this.key);\n }\n }\n}\n\nexport default Metadata;\n", "import isEqual from 'lodash/isEqual';\n\nimport Metadata from './Metadata';\nimport {\n PluginStatusError,\n PluginStatusMetadata,\n PluginStatusProcessed,\n PluginStatusProcessing\n} from './types';\n\nclass ImageProcessingMetadata extends Metadata<PluginStatusMetadata> {\n get(blockId: number): PluginStatusMetadata {\n return super.get(blockId) ?? { status: 'IDLE' };\n }\n\n /**\n * Detect if the block has been duplicated with processed or processing\n * fill processing. In that case the processing state is still\n * valid, but blockId and fillId have changed.\n */\n isDuplicate(blockId: number): boolean {\n if (!this.cesdk.engine.block.isValid(blockId)) return false;\n\n const metadata = this.get(blockId);\n\n if (\n metadata.status === 'IDLE' ||\n metadata.status === 'PENDING' ||\n metadata.status === 'ERROR'\n )\n return false;\n\n if (!this.cesdk.engine.block.hasFill(blockId)) return false;\n const fillId = this.cesdk.engine.block.getFill(blockId);\n\n // It cannot be a duplicate if the blockId or fillId are the same\n if (metadata.blockId === blockId || metadata.fillId === fillId)\n return false;\n\n return true;\n }\n\n /**\n * Fixes the metadata if the block has been duplicated, i.e. the blockId and\n * fillId will be updated to the current block/fill.\n *\n * Please note: Call this method only on duplicates (see isDuplicate).\n */\n fixDuplicate(blockId: number) {\n const fillId = this.cesdk.engine.block.getFill(blockId);\n const metadata = this.get(blockId);\n if (\n metadata.status === 'IDLE' ||\n metadata.status === 'PENDING' ||\n metadata.status === 'ERROR'\n )\n return;\n this.set(blockId, {\n ...metadata,\n blockId,\n fillId\n });\n\n // If it is currently processing the best we can do is to just recover\n // the initial image data, since no processing will update this block and\n // it will be stuck in the processing state.\n if (metadata.status === 'PROCESSING') {\n this.recoverInitialImageData(blockId);\n this.clear(blockId);\n }\n }\n\n /**\n * Check if the image has a consisten metadata state. A inconsistent state is\n * caused by outside changes of the fill data.\n *\n * @returns true if the metadata is consistent, false otherwise\n */\n isConsistent(blockId: number): boolean {\n // In case the block was removed, we just abort and mark it\n // as reset by returning true\n if (!this.cesdk.engine.block.isValid(blockId)) return false;\n const metadata = this.get(blockId);\n if (metadata.status === 'IDLE' || metadata.status === 'PENDING')\n return true;\n\n if (!this.cesdk.engine.block.hasFill(blockId)) return false;\n const fillId = this.cesdk.engine.block.getFill(blockId);\n if (fillId == null) return false;\n\n if (blockId !== metadata.blockId || fillId !== metadata.fillId)\n return false;\n\n const sourceSet = this.cesdk.engine.block.getSourceSet(\n fillId,\n 'fill/image/sourceSet'\n );\n const imageFileURI = this.cesdk.engine.block.getString(\n fillId,\n 'fill/image/imageFileURI'\n );\n\n if (\n sourceSet.length === 0 &&\n !imageFileURI &&\n metadata.status === 'PROCESSING'\n ) {\n // While we process it is OK to have no image file URI and no source set\n // (which we cleared to show the spinning loader)\n return true;\n }\n\n // Source sets have precedence over imageFileURI so if we have a source set,\n // we only need to check if it has changed to something else.\n if (sourceSet?.length > 0) {\n const initialSourceSet = metadata.initialSourceSet;\n // If we have already processed the image, we need to check if the source set\n // we need to check against both source sets, the removed and the initial\n if (metadata.status === 'PROCESSED') {\n if (\n !isEqual(sourceSet, metadata.processed) &&\n !isEqual(sourceSet, initialSourceSet)\n ) {\n return false;\n }\n } else {\n if (!isEqual(sourceSet, initialSourceSet)) {\n return false;\n }\n }\n } else {\n if (metadata.status === 'PROCESSED') {\n if (\n imageFileURI !== metadata.initialImageFileURI &&\n imageFileURI !== metadata.processed\n ) {\n return false;\n }\n } else {\n if (imageFileURI !== metadata.initialImageFileURI) {\n return false;\n }\n }\n }\n return true;\n }\n\n /**\n * Recover the initial values to avoid the loading spinner and have the same\n * state as before the fill processing was started.\n */\n recoverInitialImageData(blockId: number) {\n const blockApi = this.cesdk.engine.block;\n if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore)\n\n const metadata = this.get(blockId);\n\n if (metadata.status === 'PENDING' || metadata.status === 'IDLE') {\n return;\n }\n\n const initialSourceSet = metadata.initialSourceSet;\n const initialImageFileURI = metadata.initialImageFileURI;\n const initialPreviewFileURI = metadata.initialPreviewFileURI;\n\n const fillId = this.getValidFill(blockId, metadata);\n if (fillId == null) return;\n\n if (initialImageFileURI) {\n this.cesdk.engine.block.setString(\n fillId,\n 'fill/image/imageFileURI',\n initialImageFileURI\n );\n }\n if (initialPreviewFileURI) {\n this.cesdk.engine.block.setString(\n fillId,\n 'fill/image/previewFileURI',\n initialPreviewFileURI\n );\n }\n if (initialSourceSet.length > 0) {\n this.cesdk.engine.block.setSourceSet(\n fillId,\n 'fill/image/sourceSet',\n initialSourceSet\n );\n }\n }\n\n /**\n * Returns the fill id of the block if it has a valid fill that was used for\n * fill processing. Returns undefined otherwise.\n */\n private getValidFill(\n blockId: number,\n metadata: PluginStatusProcessing | PluginStatusError | PluginStatusProcessed\n ): number | undefined {\n if (\n !this.cesdk.engine.block.isValid(blockId) ||\n !this.cesdk.engine.block.hasFill(blockId) ||\n blockId !== metadata.blockId\n ) {\n return undefined;\n }\n const fillId = this.cesdk.engine.block.getFill(blockId);\n if (fillId !== metadata.fillId) {\n return undefined;\n }\n\n return fillId;\n }\n}\n\nexport default ImageProcessingMetadata;\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\nimport { type Source } from '@cesdk/cesdk-js';\nimport type FillProcessingMetadata from '../metadata/FillProcessingMetadata';\n\nexport default async function processFill(\n cesdk: CreativeEditorSDK,\n blockId: number,\n metadata: FillProcessingMetadata,\n processSourceSet: (sourceSet: Source[]) => Promise<Source[]>,\n processImageFileURI: (imageFileURI: string) => Promise<string>\n) {\n const blockApi = cesdk.engine.block;\n if (!blockApi.hasFill(blockId))\n throw new Error('Block has no fill to process');\n\n const fillId = blockApi.getFill(blockId);\n\n // Get the current image URI and source set as initial values.\n const initialSourceSet = blockApi.getSourceSet(\n fillId,\n 'fill/image/sourceSet'\n );\n const initialImageFileURI = blockApi.getString(\n fillId,\n 'fill/image/imageFileURI'\n );\n const initialPreviewFileURI = blockApi.getString(\n fillId,\n 'fill/image/previewFileURI'\n );\n\n try {\n // Clear values in the engine to trigger the loading spinner\n blockApi.setString(fillId, 'fill/image/imageFileURI', '');\n blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []);\n\n metadata.set(blockId, {\n ...metadata.get(blockId),\n version: PLUGIN_VERSION,\n initialSourceSet,\n initialImageFileURI,\n initialPreviewFileURI,\n blockId,\n fillId,\n status: 'PROCESSING'\n });\n\n // Sort the source set by resolution so that the highest resolution image\n // is first.\n const sortedSourceSet = initialSourceSet.sort(\n (a, b) => b.width * b.height - a.height * a.width\n );\n\n const uriToProcess =\n // Source sets have priority in the engine\n initialSourceSet.length > 0\n ? // Choose the highest resolution image in the source set\n sortedSourceSet[0].uri\n : initialImageFileURI;\n\n // If there is no initial preview file URI, set the current URI.\n // It will be used as the image displayed while showing the loading spinner.\n if (!initialPreviewFileURI) {\n blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess);\n }\n\n if (initialSourceSet.length > 0) {\n // Source set code path\n // ====================\n const newSourceSet = await processSourceSet(initialSourceSet);\n // Check for externally changed state while we were applying the mask and\n // do not proceed if the state was reset.\n if (\n metadata.get(blockId).status !== 'PROCESSING' ||\n !metadata.isConsistent(blockId)\n )\n return;\n\n // Check for externally changed state while we were uploading and\n // do not proceed if the state was reset.\n if (\n metadata.get(blockId).status !== 'PROCESSING' ||\n !metadata.isConsistent(blockId)\n )\n return;\n\n if (newSourceSet == null) return;\n\n if (newSourceSet.every((url) => url == null)) {\n throw new Error('Empty source set after processing fill');\n }\n\n metadata.set(blockId, {\n version: PLUGIN_VERSION,\n initialSourceSet,\n initialImageFileURI,\n initialPreviewFileURI,\n blockId,\n fillId,\n status: 'PROCESSED',\n processed: newSourceSet\n });\n blockApi.setSourceSet(fillId, 'fill/image/sourceSet', newSourceSet);\n // TODO: Generate a thumb/preview uri\n blockApi.setString(fillId, 'fill/image/previewFileURI', '');\n } else {\n // ImageFileURI code path\n // ======================\n const newFileURI = await processImageFileURI(uriToProcess);\n\n // Check for externally changed state while we were applying the mask and\n // do not proceed if the state was reset.\n if (\n metadata.get(blockId).status !== 'PROCESSING' ||\n !metadata.isConsistent(blockId)\n )\n return;\n\n // Check for externally changed state while we were uploading and\n // do not proceed if the state was reset.\n if (\n metadata.get(blockId).status !== 'PROCESSING' ||\n !metadata.isConsistent(blockId)\n )\n return;\n\n if (newFileURI == null) {\n throw new Error('Could not upload fill processed data');\n }\n\n metadata.set(blockId, {\n version: PLUGIN_VERSION,\n initialSourceSet,\n initialImageFileURI,\n initialPreviewFileURI,\n blockId,\n fillId,\n status: 'PROCESSED',\n processed: newFileURI\n });\n blockApi.setString(fillId, 'fill/image/imageFileURI', newFileURI);\n // TODO: Generate a thumb/preview uri\n blockApi.setString(fillId, 'fill/image/previewFileURI', '');\n }\n // Finally, create an undo step\n cesdk.engine.editor.addUndoStep();\n } catch (error) {\n if (cesdk.engine.block.isValid(blockId)) {\n metadata.set(blockId, {\n version: PLUGIN_VERSION,\n initialSourceSet,\n initialImageFileURI,\n initialPreviewFileURI,\n blockId,\n fillId,\n status: 'ERROR'\n });\n\n metadata.recoverInitialImageData(blockId);\n }\n\n if (\n error != null &&\n typeof error === 'object' &&\n 'message' in error &&\n typeof error.message === 'string'\n ) {\n cesdk.ui.showNotification({\n type: 'error',\n message: error.message\n });\n }\n\n // eslint-disable-next-line no-console\n console.log(error);\n }\n}\n", "export function getFeatureId(pluginId: string): string {\n return `${pluginId}.fillProcessing.feature`;\n}\n\nexport function getCanvasMenuComponentId(pluginId: string): string {\n return `${pluginId}.fillProcessing.canvasMenu`;\n}\n\nexport function getI18nCanvasMenuLabel(pluginId: string): string {\n return `plugin.${pluginId}.fillProcessing.canvasMenu.button.label`;\n}\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\n\nimport { FillProcessingMetadata } from '..';\nimport { getFeatureId } from './constants';\n\nexport default function handleFillProcessing(\n cesdk: CreativeEditorSDK,\n {\n pluginId,\n process\n }: {\n pluginId: string;\n icon?: string;\n process: (blockId: number, metadata: FillProcessingMetadata) => void;\n }\n): {\n featureId: string;\n} {\n const featureId = getFeatureId(pluginId);\n\n const metadata = new FillProcessingMetadata(cesdk, pluginId);\n\n enableFeatures(cesdk, metadata, featureId);\n\n cesdk.engine.event.subscribe([], async (events) => {\n events.forEach((e) => {\n const id = e.block;\n if (!cesdk.engine.block.isValid(id) || !metadata.hasData(id)) {\n return;\n }\n\n if (e.type === 'Created') {\n if (metadata.isDuplicate(id)) {\n metadata.fixDuplicate(id);\n }\n } else if (e.type === 'Updated') {\n switch (metadata.get(id).status) {\n case 'PENDING': {\n if (\n cesdk.feature.unstable_isEnabled(featureId, {\n engine: cesdk.engine\n }) &&\n cesdk.engine.block.isAllowedByScope(id, 'fill/change')\n ) {\n process(id, metadata);\n }\n break;\n }\n\n case 'PROCESSING':\n case 'PROCESSED': {\n if (!metadata.isConsistent(id)) {\n metadata.clear(id);\n }\n break;\n }\n\n default: {\n // We do not care about other states\n }\n }\n }\n });\n });\n\n return { featureId };\n}\n\n/**\n * Defines the feature that determines in which context (on which block)\n * fill processing is allowed/enabled.\n */\nfunction enableFeatures(\n cesdk: CreativeEditorSDK,\n metadata: FillProcessingMetadata,\n featureId: string\n) {\n cesdk.feature.unstable_enable(featureId, ({ engine }) => {\n const selectedIds = engine.block.findAllSelected();\n if (selectedIds.length !== 1) {\n return false;\n }\n const [selectedId] = selectedIds;\n\n if (!cesdk.engine.block.isVisible(selectedId)) return false;\n\n if (cesdk.engine.block.hasFill(selectedId)) {\n const kind = cesdk.engine.block.getKind(selectedId);\n if (kind === 'sticker') return false;\n\n const fillId = cesdk.engine.block.getFill(selectedId);\n const fillType = cesdk.engine.block.getType(fillId);\n\n if (fillType !== '//ly.img.ubq/fill/image') {\n return false;\n }\n\n const fileUri = engine.block.getString(fillId, 'fill/image/imageFileURI');\n const sourceSet = engine.block.getSourceSet(\n fillId,\n 'fill/image/sourceSet'\n );\n\n if (sourceSet.length > 0 || fileUri !== '') return true;\n\n // If we are in a processing state we do not have a imageFileURI or\n // source set set (to show the loading spinner), but the feature is still\n // enabled.\n return metadata.get(selectedId).status === 'PROCESSING';\n }\n\n return false;\n });\n}\n", "import CreativeEditorSDK from '@cesdk/cesdk-js';\nimport { FillProcessingMetadata } from '..';\nimport {\n getCanvasMenuComponentId,\n getFeatureId,\n getI18nCanvasMenuLabel\n} from './constants';\n\nexport type Location = 'canvasMenu';\n\n/**\n * Registers the components that can be used to process the fill of\n * a block.\n */\nexport default function registerFillProcessingComponents(\n cesdk: CreativeEditorSDK,\n options: {\n pluginId: string;\n icon?: string;\n locations?: Location | Location[];\n }\n): {\n canvasMenuComponentId: string;\n\n translationsKeys: {\n canvasMenuLabel: string;\n };\n} {\n const { pluginId, locations } = options;\n const metadata = new FillProcessingMetadata(cesdk, pluginId);\n\n const canvasMenuComponentId = getCanvasMenuComponentId(pluginId);\n const canvasMenuLabel = getI18nCanvasMenuLabel(pluginId);\n const featureId = getFeatureId(pluginId);\n\n if (locations?.includes('canvasMenu')) {\n cesdk.ui.unstable_setCanvasMenuOrder([\n canvasMenuComponentId,\n ...cesdk.ui.unstable_getCanvasMenuOrder()\n ]);\n }\n\n cesdk.ui.unstable_registerComponent(\n canvasMenuComponentId,\n ({ builder: { Button }, engine }) => {\n if (\n !cesdk.feature.unstable_isEnabled(featureId, {\n engine\n })\n ) {\n return;\n }\n\n const [id] = engine.block.findAllSelected();\n\n if (!cesdk.engine.block.isAllowedByScope(id, 'fill/change')) return;\n\n const currentMetadata = metadata.get(id);\n\n const isLoading = currentMetadata.status === 'PROCESSING';\n const isDisabled =\n currentMetadata.status === 'PENDING' ||\n currentMetadata.status === 'PROCESSING';\n\n let loadingProgress: number | undefined;\n if (isLoading && currentMetadata.progress) {\n const { current, total } = currentMetadata.progress;\n loadingProgress = (current / total) * 100;\n }\n\n const buttonId = `${canvasMenuComponentId}.button`;\n Button(buttonId, {\n label: canvasMenuLabel,\n icon: options.icon,\n isLoading,\n isDisabled,\n loadingProgress,\n onClick: () => {\n if (\n currentMetadata.status === 'IDLE' ||\n currentMetadata.status === 'ERROR' ||\n currentMetadata.status === 'PROCESSED'\n ) {\n metadata.set(id, {\n status: 'PENDING'\n });\n }\n }\n });\n }\n );\n\n return {\n canvasMenuComponentId,\n translationsKeys: {\n canvasMenuLabel\n }\n };\n}\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\nimport type { Source } from '@cesdk/cesdk-js';\nimport {\n applySegmentationMask,\n removeBackground,\n segmentForeground,\n type Config\n} from '@imgly/background-removal';\n\nimport { processFill, type FillProcessingMetadata } from '@imgly/plugin-utils';\n\nimport throttle from 'lodash/throttle';\n\ninterface IMGLYBackgroundRemovalProviderClientSide {\n type: '@imgly/background-removal';\n configuration?: Config;\n}\n\ninterface CustomBackgroundRemovalProvider {\n type: 'custom';\n\n /**\n * Process the image file URI and return the processed image file URI with\n * the background removed.\n *\n * @param imageFileURI - The URI of the image file to process\n * @returns The processed image file URI\n */\n processImageFileURI: (imageFileURI: string) => Promise<string>;\n\n /**\n * Process the source set and return a new source set as the input source set.\n *\n * @param sourceSet - The source set to process. It is sorted so that the highest resolution image uri is first\n * @returns the new source set with backgrounds removed\n */\n processSourceSet: (sourceSet: Source[]) => Promise<Source[]>;\n}\n\nexport type BackgroundRemovalProvider =\n | IMGLYBackgroundRemovalProviderClientSide\n | CustomBackgroundRemovalProvider;\n\n/**\n * Triggers the background removal process.\n */\nexport async function processBackgroundRemoval(\n cesdk: CreativeEditorSDK,\n blockId: number,\n metadata: FillProcessingMetadata,\n provider: BackgroundRemovalProvider\n) {\n switch (provider.type) {\n case '@imgly/background-removal': {\n const configuration = provider.configuration ?? {};\n const bgRemovalConfiguration: Config = {\n device: 'gpu',\n ...configuration,\n progress: throttle((key, current, total) => {\n const currentMetadataInProgress = metadata.get(blockId);\n if (\n currentMetadataInProgress.status !== 'PROCESSING' ||\n !metadata.isConsistent(blockId)\n )\n return;\n\n configuration.progress?.(key, current, total);\n metadata.set(blockId, {\n ...currentMetadataInProgress,\n progress: { key, current, total }\n });\n }, 100)\n };\n\n processFill(\n cesdk,\n blockId,\n metadata,\n // Process the source set\n async (sourceSet) => {\n // Source set is already sorted by resolution\n const highestResolutionUri = sourceSet[0].uri;\n\n // Preprocessing the image by creating a segmentation mask\n const mask = await segmentForeground(\n highestResolutionUri,\n configuration\n );\n\n const result = await Promise.all(\n sourceSet.map(async (source): Promise<Source> => {\n // Applying the mask to the original image\n const blob = await applySegmentationMask(\n source.uri,\n mask,\n bgRemovalConfiguration\n );\n const uploaded = await uploadBlob(blob, source.uri, cesdk);\n return {\n ...source,\n uri: uploaded\n };\n })\n );\n\n return result;\n },\n // Process the image file URI\n async (imageFileURI) => {\n const result = await removeBackground(\n imageFileURI,\n bgRemovalConfiguration\n );\n const uri = await uploadBlob(result, imageFileURI, cesdk);\n return uri;\n }\n );\n break;\n }\n\n case 'custom': {\n processFill(\n cesdk,\n blockId,\n metadata,\n provider.processSourceSet,\n provider.processImageFileURI\n );\n break;\n }\n\n default: {\n throw new Error('Unknown background removal provider');\n }\n }\n}\n\nasync function uploadBlob(\n blob: Blob,\n initialUri: string,\n cesdk: CreativeEditorSDK\n) {\n const pathname = new URL(initialUri).pathname;\n const parts = pathname.split('/');\n const filename = parts[parts.length - 1];\n\n const uploadedAssets = await cesdk.unstable_upload(\n new File([blob], filename, { type: blob.type }),\n () => {\n // TODO Delegate process to UI component\n }\n );\n\n const url = uploadedAssets.meta?.uri;\n if (url == null) {\n throw new Error('Could not upload processed fill');\n }\n return url;\n}\n", "import type CreativeEditorSDK from '@cesdk/cesdk-js';\n\nimport {\n initializeFillProcessing,\n registerFillProcessingComponents\n} from '@imgly/plugin-utils';\n\nimport {\n processBackgroundRemoval,\n type BackgroundRemovalProvider\n} from './processBackgroundRemoval';\nimport { UserInterfaceConfiguration } from './types';\n\nexport const PLUGIN_ID = '@imgly/plugin-background-removal-web';\n\nexport interface PluginConfiguration {\n ui?: UserInterfaceConfiguration;\n provider?: BackgroundRemovalProvider;\n}\n\nexport default (pluginConfiguration: PluginConfiguration = {}) => {\n return {\n initialize() {},\n\n update() {},\n\n initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) {\n initializeFillProcessing(cesdk, {\n pluginId: PLUGIN_ID,\n process: (blockId, metadata) => {\n processBackgroundRemoval(\n cesdk,\n blockId,\n metadata,\n pluginConfiguration.provider ?? {\n type: '@imgly/background-removal'\n }\n );\n }\n });\n\n const { translationsKeys } = registerFillProcessingComponents(cesdk, {\n pluginId: PLUGIN_ID,\n icon: '@imgly/icons/BGRemove',\n locations: pluginConfiguration.ui?.locations\n });\n\n cesdk.setTranslations({\n en: {\n [translationsKeys.canvasMenuLabel]: 'BG Removal'\n }\n });\n }\n };\n};\n", "import plugin, { PLUGIN_ID, type PluginConfiguration } from './plugin';\n\nconst Plugin = (pluginConfiguration?: PluginConfiguration) => ({\n name: PLUGIN_ID,\n version: PLUGIN_VERSION,\n ...plugin(pluginConfiguration)\n});\n\nexport default Plugin;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["isEqual", "Metadata", "cesdk", "key", "blockId", "value", "Metadata_default", "ImageProcessingMetadata", "metadata", "fillId", "sourceSet", "imageFileURI", "initialSourceSet", "initialImageFileURI", "initialPreviewFileURI", "FillProcessingMetadata_default", "processFill", "processSourceSet", "processImageFileURI", "blockApi", "sortedSourceSet", "a", "b", "uriToProcess", "newSourceSet", "url", "newFileURI", "error", "getFeatureId", "pluginId", "getCanvasMenuComponentId", "getI18nCanvasMenuLabel", "handleFillProcessing", "process", "featureId", "enableFeatures", "events", "e", "id", "engine", "selectedIds", "selectedId", "fileUri", "registerFillProcessingComponents", "options", "locations", "canvasMenuComponentId", "canvasMenuLabel", "Button", "currentMetadata", "isLoading", "isDisabled", "loadingProgress", "current", "total", "buttonId", "applySegmentationMask", "removeBackground", "segmentForeground", "throttle", "processBackgroundRemoval", "cesdk", "blockId", "metadata", "provider", "configuration", "bgRemovalConfiguration", "key", "current", "total", "currentMetadataInProgress", "F", "sourceSet", "highestResolutionUri", "mask", "segmentForeground", "source", "blob", "applySegmentationMask", "uploaded", "uploadBlob", "imageFileURI", "result", "removeBackground", "initialUri", "parts", "filename", "url", "PLUGIN_ID", "plugin_default", "pluginConfiguration", "cesdk", "blockId", "metadata", "processBackgroundRemoval", "translationsKeys", "v", "Plugin", "pluginConfiguration", "PLUGIN_ID", "plugin_default", "src_default"]
|
|
7
7
|
}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type CreativeEditorSDK from '@cesdk/cesdk-js';
|
|
2
|
-
import
|
|
2
|
+
import { type BackgroundRemovalProvider } from './processBackgroundRemoval';
|
|
3
3
|
import { UserInterfaceConfiguration } from './types';
|
|
4
|
+
export declare const PLUGIN_ID = "@imgly/plugin-background-removal-web";
|
|
4
5
|
export interface PluginConfiguration {
|
|
5
6
|
ui?: UserInterfaceConfiguration;
|
|
6
|
-
|
|
7
|
+
provider?: BackgroundRemovalProvider;
|
|
7
8
|
}
|
|
8
9
|
declare const _default: (pluginConfiguration?: PluginConfiguration) => {
|
|
9
10
|
initialize(): void;
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import type CreativeEditorSDK from '@cesdk/cesdk-js';
|
|
2
|
+
import type { Source } from '@cesdk/cesdk-js';
|
|
2
3
|
import { type Config } from '@imgly/background-removal';
|
|
4
|
+
import { type FillProcessingMetadata } from '@imgly/plugin-utils';
|
|
5
|
+
interface IMGLYBackgroundRemovalProviderClientSide {
|
|
6
|
+
type: '@imgly/background-removal';
|
|
7
|
+
configuration?: Config;
|
|
8
|
+
}
|
|
9
|
+
interface CustomBackgroundRemovalProvider {
|
|
10
|
+
type: 'custom';
|
|
11
|
+
/**
|
|
12
|
+
* Process the image file URI and return the processed image file URI with
|
|
13
|
+
* the background removed.
|
|
14
|
+
*
|
|
15
|
+
* @param imageFileURI - The URI of the image file to process
|
|
16
|
+
* @returns The processed image file URI
|
|
17
|
+
*/
|
|
18
|
+
processImageFileURI: (imageFileURI: string) => Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Process the source set and return a new source set as the input source set.
|
|
21
|
+
*
|
|
22
|
+
* @param sourceSet - The source set to process. It is sorted so that the highest resolution image uri is first
|
|
23
|
+
* @returns the new source set with backgrounds removed
|
|
24
|
+
*/
|
|
25
|
+
processSourceSet: (sourceSet: Source[]) => Promise<Source[]>;
|
|
26
|
+
}
|
|
27
|
+
export type BackgroundRemovalProvider = IMGLYBackgroundRemovalProviderClientSide | CustomBackgroundRemovalProvider;
|
|
3
28
|
/**
|
|
4
29
|
* Triggers the background removal process.
|
|
5
30
|
*/
|
|
6
|
-
export declare function processBackgroundRemoval(cesdk: CreativeEditorSDK, blockId: number,
|
|
31
|
+
export declare function processBackgroundRemoval(cesdk: CreativeEditorSDK, blockId: number, metadata: FillProcessingMetadata, provider: BackgroundRemovalProvider): Promise<void>;
|
|
32
|
+
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,44 +1,3 @@
|
|
|
1
|
-
import { type Source } from '@cesdk/cesdk-js';
|
|
2
|
-
export type PluginStatusIdle = {
|
|
3
|
-
status: 'IDLE';
|
|
4
|
-
};
|
|
5
|
-
export type PluginStatusPending = {
|
|
6
|
-
status: 'PENDING';
|
|
7
|
-
};
|
|
8
|
-
export type PluginStatusProcessing = {
|
|
9
|
-
version: string;
|
|
10
|
-
status: 'PROCESSING';
|
|
11
|
-
initialImageFileURI: string;
|
|
12
|
-
initialSourceSet: Source[];
|
|
13
|
-
initialPreviewFileURI: string;
|
|
14
|
-
blockId: number;
|
|
15
|
-
fillId: number;
|
|
16
|
-
progress?: {
|
|
17
|
-
key: string;
|
|
18
|
-
current: number;
|
|
19
|
-
total: number;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
export type PluginStatusProcessed = {
|
|
23
|
-
version: string;
|
|
24
|
-
status: 'PROCESSED';
|
|
25
|
-
initialImageFileURI: string;
|
|
26
|
-
initialSourceSet: Source[];
|
|
27
|
-
initialPreviewFileURI: string;
|
|
28
|
-
blockId: number;
|
|
29
|
-
fillId: number;
|
|
30
|
-
removedBackground: string | Source[];
|
|
31
|
-
};
|
|
32
|
-
export type PluginStatusError = {
|
|
33
|
-
version: string;
|
|
34
|
-
status: 'ERROR';
|
|
35
|
-
initialImageFileURI: string;
|
|
36
|
-
initialSourceSet: Source[];
|
|
37
|
-
initialPreviewFileURI: string;
|
|
38
|
-
blockId: number;
|
|
39
|
-
fillId: number;
|
|
40
|
-
};
|
|
41
|
-
export type PluginStatusMetadata = PluginStatusIdle | PluginStatusError | PluginStatusPending | PluginStatusProcessing | PluginStatusProcessed;
|
|
42
1
|
export type Location = 'canvasMenu';
|
|
43
2
|
export interface UserInterfaceConfiguration {
|
|
44
3
|
locations?: Location | Location[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imgly/plugin-background-removal-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-rc.0",
|
|
4
4
|
"description": "Background Removal plugin for the CE.SDK editor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CE.SDK",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"scripts": {
|
|
46
46
|
"start": "npm run watch",
|
|
47
47
|
"clean": "npx rimraf dist",
|
|
48
|
-
"build": "npm run clean && node scripts/build.mjs
|
|
49
|
-
"dev": "
|
|
48
|
+
"build": "npm run clean && node scripts/build.mjs",
|
|
49
|
+
"dev": "node scripts/watch.mjs",
|
|
50
50
|
"dev:types": "tsc --emitDeclarationOnly --watch --preserveWatchOutput",
|
|
51
51
|
"publish:latest": "npm run build && npm publish --tag latest --access public",
|
|
52
52
|
"publish:next": "npm run build && npm publish --tag next --access public",
|
|
@@ -69,7 +69,8 @@
|
|
|
69
69
|
"@cesdk/cesdk-js": "~1.21.0"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@imgly/background-removal": "^1.
|
|
72
|
+
"@imgly/background-removal": "^1.5.1",
|
|
73
|
+
"@imgly/plugin-utils": "*",
|
|
73
74
|
"lodash": "^4.17.21"
|
|
74
75
|
}
|
|
75
76
|
}
|
package/dist/constants.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export declare const PLUGIN_ID = "@imgly/plugin-background-removal-web";
|
|
2
|
-
export declare const CANVAS_MENU_COMPONENT_ID = "@imgly/plugin-background-removal-web.canvasMenu";
|
|
3
|
-
export declare const CANVAS_MENU_COMPONENT_BUTTON_ID = "@imgly/plugin-background-removal-web.canvasMenu.button";
|
|
4
|
-
export declare const FEATURE_ID = "@imgly/plugin-background-removal-web.feature";
|
package/dist/enableFeatures.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type CreativeEditorSDK from '@cesdk/cesdk-js';
|
|
2
|
-
import { UserInterfaceConfiguration } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* Registers the components that can be used to remove the background of
|
|
5
|
-
* a block.
|
|
6
|
-
*/
|
|
7
|
-
export declare function registerComponents(cesdk: CreativeEditorSDK, configuration?: UserInterfaceConfiguration): void;
|
package/dist/utils.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type CreativeEditorSDK from '@cesdk/cesdk-js';
|
|
2
|
-
import { PluginStatusMetadata } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* Sets the metadata for the plugin state.
|
|
5
|
-
*/
|
|
6
|
-
export declare function setPluginMetadata(cesdk: CreativeEditorSDK, id: number, metadata: PluginStatusMetadata): void;
|
|
7
|
-
/**
|
|
8
|
-
* Returns the current metadata for the plugin state. If no metadata
|
|
9
|
-
* is set on the given block, it will return an IDLE state.
|
|
10
|
-
*/
|
|
11
|
-
export declare function getPluginMetadata(cesdk: CreativeEditorSDK, id: number): PluginStatusMetadata;
|
|
12
|
-
/**
|
|
13
|
-
* If plugin metadata is set, it will be cleared.
|
|
14
|
-
*/
|
|
15
|
-
export declare function clearPluginMetadata(cesdk: CreativeEditorSDK, id: number): void;
|
|
16
|
-
/**
|
|
17
|
-
* Detect if the block has been duplicated with processed or processing
|
|
18
|
-
* background removal. In that case the background removal state is still
|
|
19
|
-
* valid, but blockId and fillId have changed.
|
|
20
|
-
*/
|
|
21
|
-
export declare function isDuplicate(cesdk: CreativeEditorSDK, blockId: number, metadata: PluginStatusMetadata): boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Fixes the metadata if the block has been duplicated, i.e. the blockId and
|
|
24
|
-
* fillId will be updated to the current block/fill.
|
|
25
|
-
*
|
|
26
|
-
* Please note: Call this method only on duplicates (see isDuplicate).
|
|
27
|
-
*/
|
|
28
|
-
export declare function fixDuplicateMetadata(cesdk: CreativeEditorSDK, blockId: number): void;
|
|
29
|
-
/**
|
|
30
|
-
* Check if the image has a consisten metadata state. A inconsistent state is
|
|
31
|
-
* caused by outside changes of the fill data.
|
|
32
|
-
*
|
|
33
|
-
* @returns true if the metadata is consistent, false otherwise
|
|
34
|
-
*/
|
|
35
|
-
export declare function isMetadataConsistent(cesdk: CreativeEditorSDK, blockId: number): boolean;
|
|
36
|
-
/**
|
|
37
|
-
* Recover the initial values to avoid the loading spinner and have the same
|
|
38
|
-
* state as before the background removal was started.
|
|
39
|
-
*/
|
|
40
|
-
export declare function recoverInitialImageData(cesdk: CreativeEditorSDK, blockId: number): void;
|