Search code examples
exposkia

expo-skia: filter an image and apply color overlay


I'm trying to use expo-skia to saturate an image and then apply an rgba color overlay above it. I took the saturation matrix from the pixi sources and it works fine. I can't understand how to add a color overlay after filtering.

My code:

import {
  BlendColor,
  ColorMatrix,
  Group,
  Image
} from '@shopify/react-native-skia'
...
<Group>
  <BlendColor color={color} mode='srcOver' />
  <Image fit='cover' image={skiaImageSource} rect={rect}>
    <ColorMatrix matrix{matrix} />
  </Image>
</Group>

gives me a saturated image but without any overlay. If I remove <ColorMatrix matrix{matrix} /> I see my overlay above the image, but the image isn't saturated of course.

The package versions I'm using:

"expo": "^46.0.0"
@shopify/react-native-skia": "0.1.141"

Could anyone help, please? Thanks.


Solution

  • I came up with the following solution:

    ...
    const canvas = useRef<SkiaView>()
    const [filteredImage, setFilteredImage] = useState<SkImage>()
    ...
    useEffect(() => {
        let timerId = setTimeout(function makeSnapshot() {
          if (!canvas.current) {
            timerId = setTimeout(makeSnapshot, MAKE_SNAPSHOT_TIMEOUT_MS)
    
            return
          }
    
          try {
            setFilteredImage(canvas.current.makeImageSnapshot())
          } catch {
            timerId = setTimeout(makeSnapshot, MAKE_SNAPSHOT_TIMEOUT_MS)
          }
        }, MAKE_SNAPSHOT_TIMEOUT_MS)
    
        return () => clearTimeout(timerId)
      }, [])
    ...
    return filteredImage ? (
        <Canvas style={canvasStyle}>
          <Rect rect={imageRect}>
            <BlendColor color={overlayColor} mode='srcOver' />
            <ImageShader fit='cover' image={filteredImage} rect={imageRect} />
            {getFilters()}
          </Rect>
        </Canvas>
      ) : (
        <Canvas ref={canvas} style={canvasStyle}>
          <Image fit='cover' image={image} rect={imageRect}>
            <ColorMatrix matrix={getSaturationMatrix()} />
          </Image>
        </Canvas>
      )