JetBrains / skiko

Kotlin Multiplatform bindings to Skia
Apache License 2.0
1.74k stars 106 forks source link

Provide a way to load an Image directly from NSData #887

Open StefanOltmann opened 3 months ago

StefanOltmann commented 3 months ago

Right now we need to convert Apple NSData to a Kotlin ByteArray, before we can load an Image from it. This memory copy doubles the memory required and turns out to be a problem for photo manager apps like Ashampoo Photos that do this for thousands of photos.

I need a way in Compose for iOS for directly decode an image from the raw bytes of NSData. This should be memory efficient and not copy to a ByteArray internally.

eymar commented 3 months ago

Hi @StefanOltmann ! please have a look at this PR https://github.com/JetBrains/skiko/pull/873/files This change should be already available in these versions: v0.7.97 v0.7.96 v0.7.95.1 v0.7.95 v0.7.94

StefanOltmann commented 3 months ago

@eymar

Thank you for a hint. I missed the change somehow. Sorry about that.

Can you explain „ // skia makes an internal copy of the nsData bytes“? Does SKIA the same with a Kotlin ByteArray?

elijah-semyonov commented 3 months ago

Yes it does. Skiko calls this Skia code in the end:

SKIKO_EXPORT KNativePointer org_jetbrains_skia_Image__1nMakeFromEncoded
  (KByte* encodedArray, KInt encodedLen) {
    sk_sp<SkData> encodedData = SkData::MakeWithCopy(encodedArray, encodedLen);
    sk_sp<SkImage> image = SkImages::DeferredFromEncodedData(encodedData);
    return reinterpret_cast<KNativePointer>(image.release());
}

But it's happening due to the fact, that Skia needs the control over the lifetime of the memory, which it will use later to rasterise the encoded image into bitmap. We could potentially seek for opportunity to share the ownership of NSData with Skia here, but it requires further investigation and isn't so trivial as aforementioned PR.

Screenshot 2024-03-11 at 16 47 27

If we find a way to make NSData* outlive the decoding of SKImage, we can ditch another copy here. I'll make a ticker for that.

StefanOltmann commented 3 months ago

Okay, so this PR fixes that I don't require to have the same bytes three times in memory as I have when I load it as NSData (first), convert it to Kotlin ByteArray (second) and give it to SKIA which makes a third copy.

Two copies in memory is better than three.

Even better would be just one copy. :)

StefanOltmann commented 3 months ago

I'll make a ticker for that.

Can you give me a link to that? Then we can close this issue.