Skip to content

Commit

Permalink
feat(vectorizer): Simplify and move into worker #2
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielHauschildt committed Feb 7, 2024
1 parent 1f17f48 commit 1a986b1
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 51 deletions.
21 changes: 11 additions & 10 deletions packages/vectorizer/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import {
setPluginMetadata
} from './utils';

import type { MessageBody } from "./worker.shared";

const runInWorker = (uri: string) => new Promise<Blob>((resolve, reject) => {
const worker = new Worker(new URL('./worker', import.meta.url), { type: 'module' });
worker.postMessage({data: uri})
worker.onmessage = (e: MessageEvent) => {
worker.onmessage = (e: MessageEvent<MessageBody>) => {
const msg = e.data
if (msg.error) {
reject (msg.error)
Expand All @@ -36,8 +37,9 @@ const runInWorker = (uri: string) => new Promise<Blob>((resolve, reject) => {
cesdk: CreativeEditorSDK,
blockId: number
) {
const uploader = cesdk.unstable_upload.bind(cesdk)
const engine = cesdk.engine; // the only function that needs the ui is the upload function
const blockApi = cesdk.engine.block;
const blockApi = engine.block;
if (!blockApi.hasFill(blockId))
throw new Error('Block has no fill to vectorize');

Expand Down Expand Up @@ -74,7 +76,6 @@ const runInWorker = (uri: string) => new Promise<Blob>((resolve, reject) => {

try {
// Clear values in the engine to trigger the loading spinner
+9
blockApi.setString(fillId, 'fill/image/imageFileURI', '');
blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []);
// ensure we show the last image while processsing. Some images don't have the preview set
Expand All @@ -95,16 +96,16 @@ const runInWorker = (uri: string) => new Promise<Blob>((resolve, reject) => {
const vectorized: Blob = await runInWorker(uriToProcess)

if (
getPluginMetadata(cesdk.engine, blockId).status !== 'PROCESSING' ||
!isMetadataConsistent(cesdk, blockId)
getPluginMetadata(engine, blockId).status !== 'PROCESSING' ||
!isMetadataConsistent(engine, blockId)
)
return;

const pathname = new URL(uriToProcess).pathname;
const parts = pathname.split('/');
const filename = parts[parts.length - 1];

const uploadedAssets = await cesdk.unstable_upload(
const uploadedAssets = await uploader(
new File([vectorized], filename, { type: vectorized.type }),
() => {
// TODO Delegate process to UI component
Expand All @@ -115,7 +116,7 @@ const runInWorker = (uri: string) => new Promise<Blob>((resolve, reject) => {
// do not proceed if the state was reset.
if (
getPluginMetadata(engine, blockId).status !== 'PROCESSING' ||
!isMetadataConsistent(cesdk, blockId)
!isMetadataConsistent(engine, blockId)
)
return;

Expand All @@ -135,9 +136,9 @@ const runInWorker = (uri: string) => new Promise<Blob>((resolve, reject) => {
});
blockApi.setString(fillId, 'fill/image/imageFileURI', url);
// Finally, create an undo step
cesdk.engine.editor.addUndoStep();
engine.editor.addUndoStep();
} catch (error) {
if (cesdk.engine.block.isValid(blockId)) {
if (engine.block.isValid(blockId)) {
setPluginMetadata(engine, blockId, {
version: PLUGIN_VERSION,
initialSourceSet,
Expand All @@ -147,7 +148,7 @@ const runInWorker = (uri: string) => new Promise<Blob>((resolve, reject) => {
status: 'ERROR'
});

recoverInitialImageData(cesdk, blockId);
recoverInitialImageData(engine, blockId);
}
// eslint-disable-next-line no-console
console.error(error);
Expand Down
12 changes: 7 additions & 5 deletions packages/vectorizer/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import {
isMetadataConsistent
} from './utils';

export interface PluginConfiguration { }
export interface PluginConfiguration {
// uploader ?
}

export default (pluginConfiguration: PluginConfiguration = {}) => {
return {
Expand Down Expand Up @@ -73,7 +75,7 @@ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) {
case 'PROCESSING':
case 'PROCESSED_TOGGLE_OFF':
case 'PROCESSED_TOGGLE_ON': {
if (!isMetadataConsistent(cesdk, blockId)) {
if (!isMetadataConsistent(cesdk.engine, blockId)) {
clearPluginMetadata(cesdk.engine, blockId);
}
break;
Expand All @@ -94,9 +96,9 @@ export function enableFeatures(cesdk: CreativeEditorSDK) {
}
const [selectedId] = selectedIds;

if (cesdk.engine.block.hasFill(selectedId)) {
const fillId = cesdk.engine.block.getFill(selectedId);
const fillType = cesdk.engine.block.getType(fillId);
if (engine.block.hasFill(selectedId)) {
const fillId = engine.block.getFill(selectedId);
const fillType = engine.block.getType(fillId);

if (fillType !== '//ly.img.ubq/fill/image') {
return false;
Expand Down
3 changes: 3 additions & 0 deletions packages/vectorizer/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ export type PluginMetadata =
| PluginStatusPending
| PluginStatusProcessing
| PluginStatusProcessed;



48 changes: 24 additions & 24 deletions packages/vectorizer/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,26 @@ export function fixDuplicateMetadata(
* @returns true if the metadata is consistent, false otherwise
*/
export function isMetadataConsistent(
cesdk: CreativeEditorSDK,
engine: CreativeEngine,
blockId: number
): boolean {
// In case the block was removed, we just abort and mark it
// as reset by returning true
if (!cesdk.engine.block.isValid(blockId)) return false;
const metadata = getPluginMetadata(cesdk.engine, blockId);
if (!engine.block.isValid(blockId)) return false;
const metadata = getPluginMetadata(engine, blockId);
if (metadata.status === 'IDLE' || metadata.status === 'PENDING') return true;

if (!cesdk.engine.block.hasFill(blockId)) return false;
const fillId = cesdk.engine.block.getFill(blockId);
if (!engine.block.hasFill(blockId)) return false;
const fillId = engine.block.getFill(blockId);
if (fillId == null) return false;

if (blockId !== metadata.blockId || fillId !== metadata.fillId) return false;

const sourceSet = cesdk.engine.block.getSourceSet(
const sourceSet = engine.block.getSourceSet(
fillId,
'fill/image/sourceSet'
);
const imageFileURI = cesdk.engine.block.getString(
const imageFileURI = engine.block.getString(
fillId,
'fill/image/imageFileURI'
);
Expand Down Expand Up @@ -185,15 +185,15 @@ export function isMetadataConsistent(
* in the state "PROCESSED_TOGGLE_OFF" or "PROCESSED_TOGGLE_ON". Otherwise do
* nothing.
*/
export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) {
const blockApi = cesdk.engine.block;
export function toggleProcessedData(engine: CreativeEngine, blockId: number) {
const blockApi = engine.block;
if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore)
const fillId = blockApi.getFill(blockId);

const metadata = getPluginMetadata(cesdk.engine, blockId);
const metadata = getPluginMetadata(engine, blockId);

if (metadata.status === 'PROCESSED_TOGGLE_OFF') {
setPluginMetadata(cesdk.engine, blockId, {
setPluginMetadata(engine, blockId, {
...metadata,
status: 'PROCESSED_TOGGLE_ON'
});
Expand All @@ -213,9 +213,9 @@ export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) {
);
}

cesdk.engine.editor.addUndoStep();
engine.editor.addUndoStep();
} else if (metadata.status === 'PROCESSED_TOGGLE_ON') {
setPluginMetadata(cesdk.engine, blockId, {
setPluginMetadata(engine, blockId, {
...metadata,
status: 'PROCESSED_TOGGLE_OFF'
});
Expand All @@ -230,7 +230,7 @@ export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) {
'fill/image/sourceSet',
metadata.initialSourceSet
);
cesdk.engine.editor.addUndoStep();
engine.editor.addUndoStep();
}
}

Expand All @@ -239,13 +239,13 @@ export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) {
* state as before the process was started.
*/
export function recoverInitialImageData(
cesdk: CreativeEditorSDK,
engine: CreativeEngine,
blockId: number
) {
const blockApi = cesdk.engine.block;
const blockApi = engine.block;
if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore)

const metadata = getPluginMetadata(cesdk.engine, blockId);
const metadata = getPluginMetadata(engine, blockId);

if (metadata.status === 'PENDING' || metadata.status === 'IDLE') {
return;
Expand All @@ -254,18 +254,18 @@ export function recoverInitialImageData(
const initialSourceSet = metadata.initialSourceSet;
const initialImageFileURI = metadata.initialImageFileURI;

const fillId = getValidFill(cesdk, blockId, metadata);
const fillId = getValidFill(engine, blockId, metadata);
if (fillId == null) return;

if (initialImageFileURI) {
cesdk.engine.block.setString(
engine.block.setString(
fillId,
'fill/image/imageFileURI',
initialImageFileURI
);
}
if (initialSourceSet.length > 0) {
cesdk.engine.block.setSourceSet(
engine.block.setSourceSet(
fillId,
'fill/image/sourceSet',
initialSourceSet
Expand All @@ -278,18 +278,18 @@ export function recoverInitialImageData(
* vectorizing. Returns undefined otherwise.
*/
function getValidFill(
cesdk: CreativeEditorSDK,
engine: CreativeEngine,
blockId: number,
metadata: PluginStatusProcessing | PluginStatusError | PluginStatusProcessed
): number | undefined {
if (
!cesdk.engine.block.isValid(blockId) ||
!cesdk.engine.block.hasFill(blockId) ||
!engine.block.isValid(blockId) ||
!engine.block.hasFill(blockId) ||
blockId !== metadata.blockId
) {
return undefined;
}
const fillId = cesdk.engine.block.getFill(blockId);
const fillId = engine.block.getFill(blockId);
if (fillId !== metadata.fillId) {
return undefined;
}
Expand Down
5 changes: 5 additions & 0 deletions packages/vectorizer/src/worker.shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface MessageBody {
method?: string,
data?: any;
error?: Error
}
40 changes: 28 additions & 12 deletions packages/vectorizer/src/worker.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import { imageToSvg } from '@imgly/vectorizer';
import type { MessageBody } from "./worker.shared";

self.onmessage = function (e) {
const uriToProcess = e.data.data;
fetch(uriToProcess)
.then(res => res.blob())
.then(blob => imageToSvg(blob))
.then(blob => blob.arrayBuffer())
.then(blob => {
postMessage({data: blob});
})
.catch(err => {
postMessage({error: err});
})

self.onmessage = function (e: MessageEvent<MessageBody>) {
const msg = e.data;


const data = msg.data ?? {}
const method = msg.method ?? '' // default to empty string
switch (method) {
case "health": {
postMessage({ data: 'ok' })
break;
}
case "imageToSvg":
default: {
const uriToProcess = data;
fetch(uriToProcess)
.then(res => res.blob())
.then(blob => imageToSvg(blob))
.then(blob => blob.arrayBuffer())
.then(blob => {
postMessage({ data: blob });
})
.catch(err => {
postMessage({ error: err });
})
}
}
}

0 comments on commit 1a986b1

Please sign in to comment.