Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement native encoder #9

Closed
emclab opened this issue Jun 20, 2020 · 11 comments
Closed

Implement native encoder #9

emclab opened this issue Jun 20, 2020 · 11 comments
Labels
Android This is an issue specifically concerning the Android implementation enhancement New feature or request help wanted Extra attention is needed

Comments

@emclab
Copy link

emclab commented Jun 20, 2020

Question

Very interesting module! My understanding is that the react-native-blurhash module only presents a blurhash at frontend. My question is that how to generate a blurhash in react-native environment. Can I use module blurhash with react-native 0.62 to generate blurhash string? Any concern about the performance at frontend? Many thanks.

Environment

paste the output of `react-native info` here
"react": PASTE_VERSION_HERE,
"react-native": PASTE_VERSION_HERE,
"react-native-blurhash": PASTE_VERSION_HERE
@emclab emclab added the question Further information is requested label Jun 20, 2020
@emclab emclab changed the title How to generate blurhash? How to generate blurhash in react-native 0.62? Jun 20, 2020
@mrousavy
Copy link
Owner

No, I don't think you could create (encode) a blurhash using react native, since the TypeScript lib requires a canvas to read the pixels from. Now I could add encoding functionality to my module, which even runs as native code, but why do you need this?

I've got an example workflow in my README, please read that. The idea is to let the server create the blurhash, there's no reason for your front end to encode it.

@emclab
Copy link
Author

emclab commented Jun 20, 2020

Nice feature to have in the module to generate hash. Since the frontend is getting more and more powerful, it makes sense to let the frontend to generate a blurhash when it uploads an image, instead of loading the server which is just a db storage. I would imagine encoding is CPU intensive.

@mrousavy
Copy link
Owner

Yes encoding isn't very fast. Although I don't think it's a good idea to use your frontend for this, I'd accept PRs implementing the feature.

How would you imagine the API structure? A function that just takes a nativeID as argument? or an ImageSource/URI?

@emclab
Copy link
Author

emclab commented Jun 22, 2020

That would be great. For decentralized storage such as IPFS, generating blurhash at frontend may be the only option. In my use case, it is the input of the image file and output of the blurhash. When a user uploads an image from her/his react-native app, an image record is generated on the server and url of the image and the blurhash are part of the record. Input of URI can be another use case. If you need me to create a PR for the feature, please let me know. Thanks.

@mrousavy
Copy link
Owner

I see. I guess an encoder won't hurt no one. I'll gladly accept any PRs regarding this, thanks

@emclab
Copy link
Author

emclab commented Jun 22, 2020

A PR has been created. Thanks.

@mrousavy
Copy link
Owner

mrousavy commented Jun 26, 2020

How exactly do you imagine the API?

I've thought about the following approaches:

URI

const blurhash = await Blurhash.encode({ uri: 'my-image-uri' });

But that would require the native module to initialize a React Image component which

  1. resolves the URI (even if it has been downloaded before)
  2. renders the Image
  3. copies all pixels of the Image into an Array
  4. dispose the Image
  5. dump the pixels into the encode Swift/Kotlin func and then
  6. resolve with the generated blurhash.

I'd imagine it being really slow and also blocking the UI thread for the time the image gets rendered (steps 2., 3. and 4.)

Step 5. can be async if the thread start overhead isn't too high.

Refs

Another approach would be using React refs:

return <Image src={{ uri: 'my-image-uri' }} ref={myImageRef} />;

and call it like this:

const blurhash = await myImageRef.encode();

This skips the first 4 steps, but isn't really typesafe and I'm not sure if I can even access the refs natively or if I have to extract pixels in JavaScript and pass them over the JSI Bridge, making this a lot slower.

Native ID

Lastly, use native IDs:

return <Image src={{ uri: 'my-image-uri' }} nativeID={myImageNativeID} />;

and call it like this:

const blurhash = await Blurhash.encode(myImageNativeID);

Not sure how nativeIDs work, but I think I can get a reference to the native component in Swift/Kotlin with that. If yes, that would skip the first 4 steps and doesn't require anything big to be passed over the JSI Bridge (only func invokation in, blurhash string out).

But it is a very ugly API design and isn't typesafe either. If the ID is wrong or the Image isn't rendered anymore it won't work.

End

tbh I'm not a big fan of this since I just don't see the use case. Creating a blurhash should be done on the server, since we got enough CPU power there, can adjust the parameters and speed up the clients.

If you @emclab, or anyone else reading this, got a working implementation of the encoding function, create a pull request and I'll gladly merge it. Personally, I prefer the first approach, passing in an URI since the API design is cleaner. You initialize your blurhash like you would initialize an Image, and then dumb it down to a Blurhash string. But that's just my opinion, who am I to judge.

@mrousavy
Copy link
Owner

mrousavy commented Jul 3, 2020

I've found the RCTImageUtils.h::RCTDecodeImageWithData function which could be used for Method #1 (URI).

Here is the source code for the React Native Image component (Android: ReactImage, iOS: RCTImage), if someone can help me find the "constructor" for an image component (basically a func that converts JS ImageSource -> UIImage) that would be really helpful.

@mrousavy mrousavy changed the title How to generate blurhash in react-native 0.62? Implement native encoder Jul 3, 2020
@mrousavy mrousavy added enhancement New feature or request help wanted Extra attention is needed and removed question Further information is requested labels Jul 3, 2020
@mrousavy
Copy link
Owner

mrousavy commented Jul 4, 2020

@mrousavy
Copy link
Owner

mrousavy commented Jul 4, 2020

@emclab It was a very difficult task and a lot of digging in the react-native source code, but I managed to get it working! A native Image encoder for React Native! I've published version 1.0.13 to npm.
Use it like this:

const blurhash = await Blurhash.encode('https://blurha.sh/assets/images/img2.jpg', 4, 3);

See: README#encoding

At the moment this only supports iOS.

@mrousavy mrousavy added the Android This is an issue specifically concerning the Android implementation label Jul 4, 2020
@mrousavy
Copy link
Owner

mrousavy commented Jul 4, 2020

I got the Android encoder working as well! Get 1.0.15 on npm!

Solved with c794388.

@mrousavy mrousavy closed this as completed Jul 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Android This is an issue specifically concerning the Android implementation enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants