@@ -90,6 +90,41 @@ class RNWebGPU : public NativeObject<RNWebGPU> {
9090 auto platformContext = _platformContext;
9191 auto callInvoker = _callInvoker;
9292
93+ // Resolve the requested alpha representation from the ImageBitmapOptions.
94+ // The options bag is the second argument for createImageBitmap(source,
95+ // options) and the sixth for the crop-rect overload createImageBitmap(
96+ // source, sx, sy, sw, sh, options). premultiplyAlpha defaults to
97+ // "default", which (like "premultiply") stores premultiplied pixels; only
98+ // "none" keeps straight alpha. The other options (crop rect, resize,
99+ // imageOrientation, colorSpaceConversion) are not yet implemented natively.
100+ bool wantPremultiplied = true ;
101+ const jsi::Value *optionsArg = nullptr ;
102+ if (count >= 2 && args[1 ].isObject ()) {
103+ optionsArg = &args[1 ];
104+ } else if (count >= 6 && args[5 ].isObject ()) {
105+ optionsArg = &args[5 ];
106+ }
107+ if (optionsArg != nullptr ) {
108+ auto options = optionsArg->getObject (runtime);
109+ if (options.hasProperty (runtime, " premultiplyAlpha" )) {
110+ auto value = options.getProperty (runtime, " premultiplyAlpha" );
111+ if (value.isString () &&
112+ value.getString (runtime).utf8 (runtime) == " none" ) {
113+ wantPremultiplied = false ;
114+ }
115+ }
116+ }
117+
118+ // Bring the decoded pixels into the representation requested via
119+ // premultiplyAlpha before wrapping them in an ImageBitmap.
120+ auto toRequestedAlpha = [wantPremultiplied](ImageData &imageData) {
121+ if (imageData.premultiplied != wantPremultiplied) {
122+ convertAlpha (imageData.data .data (), imageData.data .size (),
123+ imageData.premultiplied , wantPremultiplied);
124+ imageData.premultiplied = wantPremultiplied;
125+ }
126+ };
127+
93128 // Check if the argument is an ArrayBuffer or ArrayBufferView
94129 // (TypedArray / DataView). Only a real buffer source is run through the
95130 // ArrayBuffer converter, which validates byteOffset/byteLength against the
@@ -119,12 +154,14 @@ class RNWebGPU : public NativeObject<RNWebGPU> {
119154
120155 return Promise::createPromise (
121156 runtime,
122- [platformContext, callInvoker, dataCopy = std::move (dataCopy)](
157+ [platformContext, callInvoker, toRequestedAlpha,
158+ dataCopy = std::move (dataCopy)](
123159 jsi::Runtime & /* runtime*/ ,
124160 std::shared_ptr<Promise> promise) mutable {
125161 platformContext->createImageBitmapFromDataAsync (
126162 dataCopy,
127- [callInvoker, promise](ImageData imageData) {
163+ [callInvoker, promise, toRequestedAlpha](ImageData imageData) {
164+ toRequestedAlpha (imageData);
128165 auto imageBitmap = std::make_shared<ImageBitmap>(imageData);
129166 callInvoker->invokeAsync ([promise, imageBitmap]() {
130167 promise->resolve (
@@ -149,11 +186,12 @@ class RNWebGPU : public NativeObject<RNWebGPU> {
149186
150187 return Promise::createPromise (
151188 runtime,
152- [platformContext, callInvoker, blobId, offset,
189+ [platformContext, callInvoker, toRequestedAlpha, blobId, offset,
153190 size](jsi::Runtime & /* runtime*/ , std::shared_ptr<Promise> promise) {
154191 platformContext->createImageBitmapAsync (
155192 blobId, offset, size,
156- [callInvoker, promise](ImageData imageData) {
193+ [callInvoker, promise, toRequestedAlpha](ImageData imageData) {
194+ toRequestedAlpha (imageData);
157195 auto imageBitmap = std::make_shared<ImageBitmap>(imageData);
158196 callInvoker->invokeAsync ([promise, imageBitmap]() {
159197 promise->resolve (
0 commit comments