@@ -14,21 +14,120 @@ const SK_IMAGE_FINALIZER = new FinalizationRegistry(
1414 } ,
1515) ;
1616
17- export class Image {
18- #ptr: Deno . PointerValue ;
17+ export type ImageSource = Uint8Array | string ;
18+
19+ export class Image extends EventTarget {
20+ #token: { ptr : Deno . PointerValue } = { ptr : 0 } ;
21+ #ptr: Deno . PointerValue = 0 ;
22+ #src?: ImageSource ;
1923
2024 get _unsafePointer ( ) {
2125 return this . #ptr;
2226 }
2327
24- constructor ( data : Uint8Array | string ) {
28+ constructor ( data ?: ImageSource ) {
29+ super ( ) ;
30+ this . src = data ;
31+ }
32+
33+ get src ( ) {
34+ return this . #src;
35+ }
36+
37+ set src ( data : ImageSource | undefined ) {
38+ if ( this . #ptr !== 0 ) {
39+ sk_image_destroy ( this . #ptr) ;
40+ SK_IMAGE_FINALIZER . unregister ( this . #token) ;
41+ this . #ptr = 0 ;
42+ }
43+
44+ if ( data === undefined ) {
45+ this . #src = undefined ;
46+ this . #ptr = 0 ;
47+ this . #token. ptr = 0 ;
48+ return ;
49+ }
50+
51+ if ( typeof data === "string" ) {
52+ if ( data . match ( / ^ \s * h t t p s ? : \/ \/ / ) ) {
53+ fetch ( data . trim ( ) )
54+ . then ( ( res ) => res . arrayBuffer ( ) )
55+ . then ( ( buffer ) => {
56+ this . src = new Uint8Array ( buffer ) ;
57+ } )
58+ . catch ( ( error ) => {
59+ this . dispatchEvent (
60+ new ErrorEvent ( "error" , {
61+ error,
62+ } ) ,
63+ ) ;
64+ } ) ;
65+ return ;
66+ } else if ( data . match ( / ^ \s * d a t a : / ) ) {
67+ const comma = data . indexOf ( "," ) ;
68+ const isBase64 = data . lastIndexOf ( "base64" , comma ) !== - 1 ;
69+ const content = data . slice ( comma + 1 ) ;
70+ const buffer = isBase64
71+ ? ( Deno as any ) . core . ops . op_base64_decode ( content )
72+ : new TextEncoder ( ) . encode ( content ) ;
73+ this . src = buffer ;
74+ return ;
75+ }
76+ }
77+
2578 this . #ptr = data instanceof Uint8Array
2679 ? sk_image_from_encoded ( data , data . byteLength )
2780 : sk_image_from_file ( cstr ( data ) ) ;
81+
2882 if ( this . #ptr === 0 ) {
29- throw new Error ( "Failed to load image" ) ;
83+ const error = new Error ( "Failed to load image" ) ;
84+ queueMicrotask ( ( ) => {
85+ this . dispatchEvent (
86+ new ErrorEvent ( "error" , {
87+ error,
88+ } ) ,
89+ ) ;
90+ } ) ;
91+ throw error ;
92+ }
93+
94+ this . #token. ptr = this . #ptr;
95+ this . #src = data ;
96+
97+ if ( this . #ptr !== 0 ) {
98+ SK_IMAGE_FINALIZER . register ( this , this . #ptr, this . #token) ;
99+ }
100+
101+ queueMicrotask ( ( ) => {
102+ this . dispatchEvent ( new Event ( "load" ) ) ;
103+ } ) ;
104+ }
105+
106+ #onload?: EventListenerOrEventListenerObject ;
107+ #onerror?: EventListenerOrEventListenerObject ;
108+
109+ get onload ( ) {
110+ return this . #onload;
111+ }
112+
113+ get onerror ( ) {
114+ return this . #onerror;
115+ }
116+
117+ set onload ( fn : EventListenerOrEventListenerObject | undefined ) {
118+ if ( this . #onload) {
119+ this . removeEventListener ( "load" , this . #onload) ;
30120 }
31- SK_IMAGE_FINALIZER . register ( this , this . #ptr) ;
121+ this . #onload = fn ;
122+ if ( fn ) this . addEventListener ( "load" , fn ) ;
123+ }
124+
125+ set onerror ( fn : EventListenerOrEventListenerObject | undefined ) {
126+ if ( this . #onerror) {
127+ this . removeEventListener ( "error" , this . #onerror) ;
128+ }
129+ this . #onerror = fn ;
130+ if ( fn ) this . addEventListener ( "error" , fn ) ;
32131 }
33132
34133 static async load ( path : string | URL ) {
@@ -49,14 +148,19 @@ export class Image {
49148 }
50149
51150 get width ( ) {
151+ if ( this . _unsafePointer === 0 ) return 0 ;
52152 return sk_image_width ( this . #ptr) ;
53153 }
54154
55155 get height ( ) {
156+ if ( this . _unsafePointer === 0 ) return 0 ;
56157 return sk_image_height ( this . #ptr) ;
57158 }
58159
59160 [ Symbol . for ( "Deno.customInspect" ) ] ( ) {
161+ if ( this . _unsafePointer === 0 ) {
162+ return `Image { pending, src: ${ Deno . inspect ( this . src ) } }` ;
163+ }
60164 return `Image { width: ${ this . width } , height: ${ this . height } }` ;
61165 }
62166}
0 commit comments