22#include < Babylon/JsRuntime.h>
33#include < Babylon/JsRuntimeScheduler.h>
44#include < Babylon/Graphics/DeviceContext.h>
5+ #include < Babylon/Polyfills/Blob.h>
56
67#include < napi/napi.h>
78
@@ -15,7 +16,7 @@ namespace Babylon::Plugins
1516{
1617 namespace
1718 {
18- std::shared_ptr <std::vector<uint8_t >> EncodePNG (const std::vector<uint8_t >& pixelData, uint32_t width, uint32_t height, bool invertY)
19+ std::unique_ptr <std::vector<std::byte >> EncodePNG (const std::vector<uint8_t >& pixelData, uint32_t width, uint32_t height, bool invertY)
1920 {
2021 auto memoryBlock{bx::MemoryBlock (&Graphics::DeviceContext::GetDefaultAllocator ())};
2122 auto writer{bx::MemoryWriter (&memoryBlock)};
@@ -35,28 +36,22 @@ namespace Babylon::Plugins
3536 throw std::runtime_error (" Failed to encode PNG image: output is empty" );
3637 }
3738
38- auto result{std::make_shared <std::vector<uint8_t >>(byteLength)};
39+ auto result{std::make_unique <std::vector<std::byte >>(byteLength)};
3940 std::memcpy (result->data (), memoryBlock.more (0 ), byteLength);
4041
4142 return result;
4243 }
4344
4445 Napi::Value EncodeImageAsync (const Napi::CallbackInfo& info)
4546 {
46- auto buffer{info[0 ].As <Napi::Uint8Array >()};
47+ auto buffer{info[0 ].As <Napi::TypedArray >()}; // ArrayBufferView
4748 auto width{info[1 ].As <Napi::Number>().Uint32Value ()};
4849 auto height{info[2 ].As <Napi::Number>().Uint32Value ()};
49- auto mimeType{info[3 ].As <Napi::String>().Utf8Value ()};
50- auto invertY{info[4 ].As <Napi::Boolean> ().Value ()};
50+ // auto mimeType{info[3].As<Napi::String>().Utf8Value()}; // Discard for now, only PNG is supported
51+ auto invertY{info. Length () > 4 && info [4 ].ToBoolean ().Value ()};
5152
5253 auto env{info.Env ()};
5354 auto deferred{Napi::Promise::Deferred::New (env)};
54-
55- if (mimeType != " image/png" )
56- {
57- deferred.Reject (Napi::Error::New (env, " Unsupported mime type: " + mimeType + " . Only image/png is currently supported." ).Value ());
58- return deferred.Promise ();
59- }
6055
6156 if (buffer.ByteLength () != width * height * 4 )
6257 {
@@ -65,14 +60,15 @@ namespace Babylon::Plugins
6560 }
6661
6762 auto runtimeScheduler{std::make_shared<JsRuntimeScheduler>(JsRuntime::GetFromJavaScript (env))};
68- auto pixelData{std::vector<uint8_t >(buffer.Data (), buffer.Data () + buffer.ByteLength ())};
63+ auto start = static_cast <uint8_t *>(buffer.ArrayBuffer ().Data ()) + buffer.ByteOffset ();
64+ auto pixelData{std::vector<uint8_t >(start, start + buffer.ByteLength ())};
6965
7066 arcana::make_task (arcana::threadpool_scheduler, arcana::cancellation_source::none (),
7167 [pixelData{std::move (pixelData)}, width, height, invertY]() {
7268 return EncodePNG (pixelData, width, height, invertY);
7369 })
7470 .then (*runtimeScheduler, arcana::cancellation_source::none (),
75- [runtimeScheduler, deferred, env](const arcana::expected<std::shared_ptr <std::vector<uint8_t >>, std::exception_ptr>& result) {
71+ [runtimeScheduler, deferred, env](const arcana::expected<std::unique_ptr <std::vector<std::byte >>, std::exception_ptr>& result) {
7672 // TODO: Crash risk on JS teardown - this async work isn't tied to any JS object lifetime,
7773 // unlike other plugins that cancel / clean up pending work in their destructors.
7874 if (result.has_error ())
@@ -81,10 +77,9 @@ namespace Babylon::Plugins
8177 return ;
8278 }
8379
84- auto & imageData = result.value ();
85- auto arrayBuffer{Napi::ArrayBuffer::New (env, imageData->data (), imageData->size (), [imageData](Napi::Env, void *) {})};
86-
87- deferred.Resolve (arrayBuffer);
80+ auto blob{Babylon::Polyfills::Blob::CreateInstance (env, std::move (*result.value ()), " image/png" )};
81+
82+ deferred.Resolve (blob);
8883 });
8984
9085 return deferred.Promise ();
0 commit comments