Closed CanRau closed 2 years ago
import { Skia } from '@shopify/react-native-skia'
Skia.Data.fromBase64(base64: string): Data
Skia.Data.fromBytes(bytes: Uint8Array): Data
Skia.Data.fromURI(uri: string): Promise<Data>
https://github.com/Shopify/react-native-skia/blob/main/package/src/skia/Data/Data.ts
Thanks for the quick response, took me a little to get from there to find MakeImageFromEncoded
const imageData = await Skia.Data.fromURI(`file://${photo.path}`);
const image = Skia.MakeImageFromEncoded(imageData)
it's not erroring anymore but my screen stays blank, tried to map as well as just render the first (just in case)
import React, { useEffect, useState } from "react";
import { SafeAreaView } from "react-native-safe-area-context";
import { PhotoFile } from "react-native-vision-camera";
import {
Skia,
Canvas,
Image,
SkImage,
} from "@shopify/react-native-skia";
import { RootStackScreenProps } from "../types";
type Image = PhotoFile & {
image: SkImage | null;
};
export const SkiaScreen = ({ navigation, route }: RootStackScreenProps<"Skia">) => {
const { photos } = route.params;
const [images, setImages] = useState<Array<Image>>([]);
const readImages = async (): Promise<Array<Image>> => {
const imgs: Array<Image> = [];
for (const photo of photos) {
const imageData = await Skia.Data.fromURI(`file://${photo.path}`);
imgs.push({ ...photo, image: Skia.MakeImageFromEncoded(imageData) });
}
return imgs;
};
useEffect(() => {
readImages()
.then((imgs) => setImages(imgs))
.catch(() => console.log("errored"));
}, []);
if (photos?.length < 1) {
if (navigation.canGoBack()) {
navigation.goBack();
}
navigation.navigate("Camera");
return null;
}
return (
<SafeAreaView>
<Canvas style={{ flex: 1 }}>
{images.length > 0 && images[0].image !== null && (
<Image
key={images[0].path}
image={images[0].image}
width={images[0].image.width()}
height={images[0].image.height()}
fit="contain"
x={0}
y={0}
/>
)}
{/* {images.map((img) => {
if (!img.image) return null;
return (
<Image
key={img.path}
image={img.image}
width={img.width}
height={img.height}
fit="scaleDown"
x={0}
y={0}
/>
);
})} */}
</Canvas>
</SafeAreaView>
);
};
img.image
is the SkImage
, the rest is PhotoFile
by RN Vision Camera which contains width, height, path and other metadata.
any obvious mistake I'm making?
Interestingly the above code works when removing the SafeAreaView
though the images.map
doesn't work either way even when setting fit="contain"
instead of scaleDown
🤔
Can you return an empty tag instead of null
in your map function and see what happens?
Also width
and height
are functions
{images.map((img) => {
if (!img.image) return <></>;
return (
<Image
key={img.path}
image={img.image}
width={img.width()}
height={img.height()}
fit="scaleDown"
x={0}
y={0}
/>
);
})}
Returning <></>
didn't change anything
Yea in the single image code I'm using it like this images[0].image.width()
the map code is accessing width={img.width}
which comes from PhotoFile
so img.image
is the SkImage
I was actually sure I tried img.image.width()
as well but it looks like I didn't as it's now working, I didn't think those would make such a difference, also I was sure I tried to enter manual numbers, which didn't work (if I did) and now that also works. 🤷🏻♂️
So thanks for your time and sorry for the confusion, though I still don't understand why some manually entered numbers work and others don't which seems to be the reason width={img.width}
doesn't work.
Edit: I thought, like with react-native Image
, I could enter whatever sizes to "scale" the images, an alternative I just found would be a <Group>
around the image with a scale transform I guess.
Edit2: Might be better in a new issue? I'm still not able to wrap my <Canvas>
in a RN <View>
or import { SafeAreaView } from "react-native-safe-area-context";
The rest of the content works, the canvas just vanishes it seems
I would be interested to investigate the issue, is there a minimal reproducible example you could provide us with?
I was trying to prepare a repro but so far I can't reproduce, even in my actual codebase, not sure what went wrong 🤷🏻♂️ I'll keep observing but for now looks like I'm good. Thanks a lot for your efforts 🙏🥰. Reopening if it happens again.
Prefixing file://
in case of iOS worked for me.
const imgData = await Skia.Data.fromURI(
`${Platform.OS === "android" ? "" : "file://"}${_uri}`
);
const image = Skia.Image.MakeImageFromEncoded(imgData);
setSnapShot(image);
Just adding this here if anyone runs into this in the future.
Solution >>> Set a default width and height to the canvas
const width = 256;
const height = 256;
const image = useImage("https://picsum.photos/200/300"); // Doesn't matter, you could load the image anywhere
<Canvas style={{ width, height }}>
<Image
image={image}
fit="fitWidth"
x={0}
y={0}
width={image?.width()}
height={image?.height()}
/>
</Canvas>
Hey amazing people, I'm really impressed by RN Skia and my opportunity to finally get more into shaders and stuff 😍
Unfortunately I couldn't find a way to load an image from the file system into Skia.
So I take pictures with RN Vision Camera which gives me a temp path like the following
/data/user/0/com.example.app/cache/mrousavy6579149888239818134.jpg
, which I pass 1 to many to another screen, in a normal RN Image component I load it by prependingfile://
. I also tried base64 encodedFileSystem.readAsStringAsync
prepended withdata:image/jpeg;base64,
Though I'm not sure how to combine that with RN-Skias
useImage
hook in an async way 🤯Tried to search the repo for examples and inspiration, but couldn't get anything off of it so far, what am I missing?