diff options
author | bobzel <zzzman@gmail.com> | 2025-08-14 13:02:53 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2025-08-14 13:02:53 -0400 |
commit | cabd82bea8eb4c69f60c8b5d4f987cf484123ecd (patch) | |
tree | 00430ea11b9eaa0dc032a8f7941849bbb9e0bf44 | |
parent | 467f1c2543626a50d48c84669cd408571260f147 (diff) |
moved background removal code into ImageUtils
-rw-r--r-- | src/client/util/Import & Export/ImageUtils.ts | 48 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 61 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/DashFieldView.tsx | 2 | ||||
-rw-r--r-- | src/workers/image.worker.ts | 5 |
4 files changed, 65 insertions, 51 deletions
diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index eae3460b3..e2eab9010 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -1,9 +1,11 @@ import { ClientUtils } from '../../../ClientUtils'; import { Doc } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { Upload } from '../../../server/SharedMediaTypes'; +import { Docs, DocumentOptions } from '../../documents/Documents'; import { Networking } from '../../Network'; export namespace ImageUtils { @@ -31,4 +33,50 @@ export namespace ImageUtils { a.download = `Dash Export [${StrCast(collection.title)}].zip`; a.click(); }; + + export function convertImgBlobToDataURL(blob: unknown) { + return new Promise<string | ArrayBuffer | null>((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = e => reject(e); + reader.readAsDataURL(blob as Blob); + }); + }; + export function createImageDocFromBlob(blob: Blob, options: DocumentOptions, docId: string, nativeWidth: number, nativeHeight: number): Promise<Doc> { + return new Promise((resolve, reject) => { + convertImgBlobToDataURL(blob).then(durl => { + ClientUtils.convertDataUri(durl as string, docId + '_noBgd').then(url => { + const imageSnapshot = Docs.Create.ImageDocument(url, options); + Doc.SetNativeWidth(imageSnapshot[DocData], nativeWidth); + Doc.SetNativeHeight(imageSnapshot[DocData], nativeHeight); + resolve(imageSnapshot); + }).catch(reject); + }).catch(reject); + }); + } + let backgroundRemovalWorker: Worker|undefined; + const workerCallbackMap = new Map<string, (result: Doc) => void>(); + function getBackgroundRemovalWorker() { + if (backgroundRemovalWorker) return backgroundRemovalWorker; + backgroundRemovalWorker = new Worker('/image.worker.js', { type: 'module' }); + backgroundRemovalWorker.onerror = (e: ErrorEvent) => console.error('Worker failed:', e); // worker.terminate(); + backgroundRemovalWorker.onmessage = async (event: MessageEvent) => { + if (event.data.success) { + createImageDocFromBlob(event.data.result, event.data.options, event.data.docId, event.data.nativeWidth, event.data.nativeHeight) + .then(imageSnapshot => { + workerCallbackMap.get(event.data.docId)?.(imageSnapshot); + workerCallbackMap.delete(event.data.docId); + }) + } else { + console.error('Error in background removal:', event.data.error); + } + // worker.terminate(); + }; + return backgroundRemovalWorker; + + } + export function removeImgBackground(options:DocumentOptions, cb: (result: Doc) => void, docId: string, nativeWidth:number, nativeHeight:number, docImgPath: string) { + workerCallbackMap.set(docId, cb); // Store the callback by docId (or use a unique requestId) + getBackgroundRemovalWorker().postMessage({ imagePath: docImgPath, options, docId, nativeWidth, nativeHeight }); + }; } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index cc747eb32..c4a731078 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -46,6 +46,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { FocusViewOptions } from './FocusViewOptions'; import './ImageBox.scss'; import { OpenWhere } from './OpenWhere'; +import { ImageUtils } from '../../util/Import & Export/ImageUtils'; const DefaultPath = '/assets/unknown-file-icon-hi.png'; export class ImageEditorData { @@ -388,56 +389,22 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { this._props.bringToFront?.(cropping); return cropping; }; - - static _worker?: Worker; - static removeImgBackground = (doc: Doc, addDoc: (doc: Doc | Doc[], annotationKey?: string) => boolean, docImgPath: string) => { - ImageEditorData.AddDoc = addDoc; - ImageEditorData.RootDoc = doc; - if (ImageBox._worker) return ImageBox._worker; - const worker = new Worker('/image.worker.js', { type: 'module' }); - worker.onmessage = async (event: MessageEvent) => { - const { success, result, error } = event.data; - if (success) { - const blobToDataURL = (blob: any) => { - return new Promise<string | ArrayBuffer | null>((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => resolve(reader.result); - reader.onerror = error => reject(error); - reader.readAsDataURL(blob); - }); - }; - blobToDataURL(result).then(durl => { - ClientUtils.convertDataUri(durl as string, doc[Id] + '_noBgd').then(url => { - const width = NumCast(doc._width) || 1; - const height = NumCast(doc._height); - const imageSnapshot = Docs.Create.ImageDocument(url, { - _nativeWidth: Doc.NativeWidth(doc), - _nativeHeight: Doc.NativeHeight(doc), - x: NumCast(doc.x) + width, - y: NumCast(doc.y), - _width: 150, - _height: (height / width) * 150, - title: 'bgremoved:' + doc.title, - }); - Doc.SetNativeWidth(imageSnapshot[DocData], Doc.NativeWidth(doc)); - Doc.SetNativeHeight(imageSnapshot[DocData], Doc.NativeHeight(doc)); - addDoc?.(imageSnapshot); - }); - }); - } else { - console.error('Error in background removal:', error); - } - // worker.terminate(); - }; - worker.onerror = (e: ErrorEvent) => console.error('Worker failed:', e); // worker.terminate(); - - worker.postMessage({ imagePath: docImgPath }); - return worker; - }; removeBackground = () => { const field = ImageCast(this.dataDoc[this.fieldKey]); if (field && this._props.addDocument) { - ImageBox.removeImgBackground(this.rootDoc, this._props.addDocument, this.choosePath(field.url)); + const doc = this.Document; + const width = NumCast(doc._width) || 1; + const height = NumCast(doc._height); + const options ={ + _nativeWidth: Doc.NativeWidth(doc), + _nativeHeight: Doc.NativeHeight(doc), + x: NumCast(doc.x) + width, + y: NumCast(doc.y), + _width: 150, + _height: (height / width) * 150, + title: 'bgremoved:' + doc.title, + } + ImageUtils.removeImgBackground(options, this._props.addDocument, this.Document[Id], Doc.NativeWidth(doc), Doc.NativeHeight(doc), this.choosePath(field.url)); } }; diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 6e3bdc5e8..5b95ac127 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -29,7 +29,6 @@ import { FormattedTextBox } from './FormattedTextBox'; @observer export class DashFieldViewMenu extends AntimodeMenu<AntimodeMenuProps> { - // eslint-disable-next-line no-use-before-define static Instance: DashFieldViewMenu; static createFieldView: (e: React.MouseEvent) => void = emptyFunction; static toggleFieldHide: () => void = emptyFunction; @@ -262,7 +261,6 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi render() { return ( <div - // eslint-disable-next-line no-use-before-define className={`dashFieldView${this.isRowActive() ? '-active' : ''}`} ref={this._fieldRef} style={{ diff --git a/src/workers/image.worker.ts b/src/workers/image.worker.ts index d069742f3..c6db44d03 100644 --- a/src/workers/image.worker.ts +++ b/src/workers/image.worker.ts @@ -1,16 +1,17 @@ import { removeBackground } from '@imgly/background-removal'; self.onmessage = async (event: MessageEvent) => { - const { imagePath, doc, addDoc } = event.data; + const { imagePath, options, nativeWidth, nativeHeight, docId } = event.data; try { // Perform the background removal const result = await removeBackground(imagePath); // Send the result back to the main thread - self.postMessage({ success: true, result, doc, addDoc }); + self.postMessage({ success: true, result, options, nativeWidth, nativeHeight, docId }); } catch (error) { // Send the error back to the main thread + // eslint-disable-next-line @typescript-eslint/no-explicit-any self.postMessage({ success: false, error: (error as any).message }); } }; |