@@ -52,16 +52,60 @@ export class ImageProcessor {
5252 }
5353 }
5454
55+ /**
56+ * Convert array buffer to canvas
57+ */
5558 static async prepareCanvas ( file : ArrayBuffer ) : Promise < Canvas > {
56- const img = await loadImage ( file ) ;
59+ if ( file instanceof Canvas ) return file ;
5760
61+ const img = await loadImage ( file ) ;
5862 const canvas = createCanvas ( img . width , img . height ) ;
5963 const ctx = canvas . getContext ( "2d" ) ;
6064
6165 ctx . drawImage ( img , 0 , 0 ) ;
6266 return canvas ;
6367 }
6468
69+ /**
70+ * Convert canvas to array buffer
71+ */
72+ static async prepareBuffer ( canvas : Canvas ) : Promise < ArrayBuffer > {
73+ if ( canvas instanceof ArrayBuffer ) return canvas ;
74+
75+ if ( typeof canvas . toBuffer === "function" ) {
76+ const buffer = canvas . toBuffer ( "image/png" ) ;
77+ const arrayBuffer = new ArrayBuffer ( buffer . byteLength ) ;
78+
79+ new Uint8Array ( arrayBuffer ) . set ( new Uint8Array ( buffer ) ) ;
80+ return arrayBuffer ;
81+ }
82+
83+ if ( typeof canvas . toDataURL === "function" ) {
84+ const dataURL = canvas . toDataURL ( "image/png" ) ;
85+ const base64Data = dataURL . replace ( / ^ d a t a : i m a g e \/ p n g ; b a s e 6 4 , / , "" ) ;
86+
87+ const buffer = Buffer . from ( base64Data , "base64" ) ;
88+ const arrayBuffer = new ArrayBuffer ( buffer . byteLength ) ;
89+
90+ new Uint8Array ( arrayBuffer ) . set ( new Uint8Array ( buffer ) ) ;
91+ return arrayBuffer ;
92+ }
93+
94+ const ctx = canvas . getContext ( "2d" ) ;
95+ const imageData = ctx . getImageData ( 0 , 0 , canvas . width , canvas . height ) ;
96+ let canvasBuffer = new ArrayBuffer ( imageData . data . byteLength ) ;
97+
98+ new Uint8Array ( canvasBuffer ) . set (
99+ new Uint8Array (
100+ imageData . data . buffer ,
101+ imageData . data . byteOffset ,
102+ imageData . data . byteLength ,
103+ ) ,
104+ ) ;
105+
106+ return canvasBuffer ;
107+ }
108+
65109 /**
66110 * Initialize OpenCV runtime, this is recommended to be called before any image processing
67111 */
@@ -84,7 +128,7 @@ export class ImageProcessor {
84128 */
85129 execute < Name extends NameWithRequiredOptions > (
86130 operationName : Name ,
87- options : OperationOptions < Name >
131+ options : OperationOptions < Name > ,
88132 ) : this;
89133
90134 /**
@@ -94,7 +138,7 @@ export class ImageProcessor {
94138 */
95139 execute < Name extends NameWithOptionalOptions > (
96140 operationName : Name ,
97- options ?: Partial < OperationOptions < Name > >
141+ options ?: Partial < OperationOptions < Name > > ,
98142 ) : this;
99143
100144 /**
@@ -104,7 +148,7 @@ export class ImageProcessor {
104148 */
105149 execute < Name extends OperationName > (
106150 operationName : Name ,
107- options ?: OperationOptions < Name > | Partial < OperationOptions < Name > >
151+ options ?: OperationOptions < Name > | Partial < OperationOptions < Name > > ,
108152 ) : this {
109153 if ( ! registry . hasOperation ( operationName ) ) {
110154 throw new Error ( `Operation "${ operationName } " not found` ) ;
@@ -114,7 +158,7 @@ export class ImageProcessor {
114158 const result = executeOperation (
115159 operationName ,
116160 this . img ,
117- options as Partial < OperationOptions < Name > > | undefined
161+ options as Partial < OperationOptions < Name > > | undefined ,
118162 ) ;
119163
120164 this . img = result . img ;
@@ -196,7 +240,7 @@ export class ImageProcessor {
196240 */
197241
198242 morphologicalGradient (
199- options : Partial < MorphologicalGradientOptions > = { }
243+ options : Partial < MorphologicalGradientOptions > = { } ,
200244 ) : this {
201245 return this . execute ( "morphologicalGradient" , options ) ;
202246 }
0 commit comments