Skia useImage fails without error #2818
Replies: 5 comments 5 replies
-
Update: I decided to try to preload and cache the images instead of relying on const imgFactory = Skia.Image.MakeImageFromEncoded.bind(Skia.Image)
const lineBottom = require('~eldrum/assets/graphics/line-bottom.png') as string
const lineTop = require('~eldrum/assets/graphics/line-top.png') as string
const LINE_WIDTH = 1000
const LEFT_SIDES = [
require('~eldrum/assets/graphics/button-left.png'),
require('~eldrum/assets/graphics/button-left-2.png'),
require('~eldrum/assets/graphics/button-left-3.png')
] as string[]
const RIGHT_SIDES = [
require('~eldrum/assets/graphics/button-right.png'),
require('~eldrum/assets/graphics/button-right-2.png'),
require('~eldrum/assets/graphics/button-right-3.png')
] as string[]
class ButtonBackgroundImageCache {
cachedImages?: {
lineTop: SkImage
lineBottom: SkImage
left: SkImage[]
right: SkImage[]
}
async cacheImage(source: string): Promise<SkImage> {
const uri = typeof source === 'string' ? source : Image.resolveAssetSource(source).uri
const data = await Skia.Data.fromURI(uri)
const image = imgFactory(data)
if (!image) {
throw new Error('Failed to load image')
}
return image
}
async generateCache() {
this.cachedImages = {
lineTop: await this.cacheImage(lineTop),
lineBottom: await this.cacheImage(lineBottom),
left: await Promise.all(LEFT_SIDES.map(this.cacheImage.bind(this))),
right: await Promise.all(RIGHT_SIDES.map(this.cacheImage.bind(this)))
}
}
}
export const buttonBackgroundCache = new ButtonBackgroundImageCache()
// I call buttonBackgroundCache.generateCache() on app startup, and I'll then use buttonBackgroundCache.cachedImages in my button background component. This kind of solved the issue and the button backgrounds are generated much faster. BUT now I'm noticing that some backgrounds fail to render altogether (i.e. all parts). |
Beta Was this translation helpful? Give feedback.
-
Ok, so it renders fine sometimes, and sometimes not. I've never seen another RN library show such inconsistent errors. I'm out. ssieu.mp4 |
Beta Was this translation helpful? Give feedback.
-
Tried upgrading to I should add that it does seem like the loading isn't the issue. I'm saying that because I'm now at a point where I'm preloading the images for the buttons but not for the bigger "card" background - that one still uses UPDATE: I should also add that the failure to render does not happen when I use return createPicture(
canvas => {
const paint = Skia.Paint()
const topOffset = (randomNumberA * LINE_WIDTH) / 6
const bottomOffset = (randomNumberB * LINE_WIDTH) / 6
const lineWidth = width - roundedSideWidth * 2
// Draw background rect
paint.setColor(Skia.Color(tint))
canvas.drawRect(
{
x: sideWidth,
y: lineThickness,
height: height - lineThickness * 4,
width: width - sideWidth * 2
},
paint
)
// Draw left side
canvas.drawImageRect(
leftSideImage,
{ x: 0, y: 0, width: 160, height: 160 },
{ x: 0, y: 0, width: roundedSideWidth, height },
paint
)
// Draw top line with mask
canvas.save()
canvas.clipRect(
{ x: roundedSideWidth, y: 0, width: lineWidth, height: LINE_HEIGHT },
ClipOp.Intersect,
true
)
canvas.drawImageRect(
lineTopImage,
{ x: 0, y: 0, width: LINE_WIDTH, height: LINE_HEIGHT },
{ x: roundedSideWidth, y: 0, width: lineWidth + topOffset, height: LINE_HEIGHT },
paint
)
canvas.restore()
// Draw bottom line with mask
canvas.save()
canvas.clipRect(
{
x: roundedSideWidth,
y: height - lineThickness,
width: lineWidth,
height: lineThickness
},
ClipOp.Intersect,
true
)
canvas.drawImageRect(
lineBottomImage,
{ x: 0, y: 0, width: LINE_WIDTH, height: LINE_HEIGHT },
{
x: roundedSideWidth,
y: height - lineThickness,
width: lineWidth + bottomOffset,
height: lineThickness
},
paint
)
canvas.restore()
// Draw right side
canvas.drawImageRect(
rightSideImage,
{ x: 0, y: 0, width: 160, height: 160 },
{
x: width - roundedSideWidth,
y: 0,
width: roundedSideWidth,
height
},
paint
)
} |
Beta Was this translation helpful? Give feedback.
-
I ended up rewriting both components using I did noticed thought that there were many more issues in 1.7.5 so I probably won't be upgrading anytime soon. |
Beta Was this translation helpful? Give feedback.
-
Hello Adam, Thank you for posting this. Your intuition of building your own loaders is correct. We offer I just had a look at the screen recording. is there any chance you could reproduce the issue in a small standalone example? is it possible that you are dealing with texture cache busting somehow? https://shopify.github.io/react-native-skia/docs/animations/textures/ maybe useImage as texture is what you need? |
Beta Was this translation helpful? Give feedback.
-
I'm currently replacing my old 9-slice button solution with Skia, but I'm having issue with
useImage
. Quite often, one or several of the images fail to load, but they do so without any error message. It happens on both iOS and Android, but more frequently on iOS.Note: I should probably add that I'm primarily looking for the most performant way to create these buttons (in various sizes and colors). Perhaps there are better ways? Path effects? Atlas? Creating snapshots of pre-rendered button backgrounds and reusing them?
Skia.image.load.fail.mp4
The left sides of the buttons do not seem to fail, or at least not as often. I suspect it could have to do with the load that is caused. The left side image is the first one in the button component.
Another example.
Example.mp4
As you can see, whenever a button renders, there seems to be chance that it completely fails. This happens both in simulators and real devices and in both debug and release builds. Images are bundled assets, they're not loaded remotely. My previous implementation (using expo-image and regular views) was constructed in a similar fashion but never failed in image loading.
Button component
Button Background component
Skia image component
Beta Was this translation helpful? Give feedback.
All reactions