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

makeImageFromView. Android crash when attempting to create an image from a view that is outside the viewport. #2265

Open
chiefchief opened this issue Mar 4, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@chiefchief
Copy link

Description

I'm implementing a signature pad feature where users can update their signature. Upon updating, I need to capture the user's first and last name and take a screenshot. However, my view is located outside the viewport. I'm using Expo for development. Interestingly, everything works fine when the app is in debug mode. However, upon building the internal distribution version, the app crashes.

Below is the crash report from Sentry.
Screenshot 2024-03-04 at 12 54 13

Version

^0.1.240

Steps to reproduce

described above

Snack, code example, screenshot, or link to a repository

import { Canvas, Path, Skia, makeImageFromView, useCanvasRef, useTouchHandler } from '@shopify/react-native-skia';
import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
import { Image, Text, View, useWindowDimensions } from 'react-native';

const activePath = Skia.Path.Make();

type SignatureProps = {
  width: number;
  height: number;
  data: { name: string; secondName: string };
  onUpdate?: (img: string) => void;
};

export const Signature: FC<SignatureProps> = ({ height, width, data, onUpdate }) => {
  const { width: screenWidth } = useWindowDimensions();
  const viewRef = useRef<View>(null);
  const canvasRef = useCanvasRef();
  const [imageSrc, setImageSrc] = useState('');

  useEffect(() => {
    return () => {
      activePath.reset();
    };
  }, []);

  const onTouch = useTouchHandler({
    onStart: ({ x, y }) => {
      activePath.moveTo(x, y);
    },
    onActive: ({ x, y }) => {
      activePath.lineTo(x, y);
    },
    onEnd: () => {
      const tempImage = canvasRef.current?.makeImageSnapshot();
      const resImage = tempImage?.encodeToBase64();
      if (resImage) {
        setImageSrc(`data:image/png;base64,${resImage}`);
      }
    },
  });

  const onLoad = useCallback(() => {
    // crash here
    makeImageFromView(viewRef).then((res) => {
      const base64Image = res?.encodeToBase64();
      if (base64Image) {
        onUpdate?.(base64Image);
      }
    });
  }, [onUpdate]);

  return (
    <>
      <View ref={viewRef} style={{ position: 'absolute', left: screenWidth }}>
        <View style={{ flexDirection: 'row' }}>
          <View style={{ flex: 1 }}>
            <Text>{`Name: ${data.name}`}</Text>
          </View>
          <View style={{ flex: 1, alignItems: 'flex-end' }}>
            <Text>{`Second Name: ${data.secondName}`}</Text>
          </View>
        </View>
        {imageSrc && <Image source={{ uri: imageSrc }} style={{ width, height }} onLoad={onLoad} />}
      </View>
      <Canvas ref={canvasRef} style={{ height, width, backgroundColor: 'white' }} onTouch={onTouch}>
        <Path path={activePath} style={'stroke'} strokeWidth={2} />
      </Canvas>
    </>
  );
};
@chiefchief chiefchief added the bug Something isn't working label Mar 4, 2024
@chanphiromsok
Copy link

I have the same issue https://shopify.github.io/react-native-skia/docs/canvas/overview
just copy and paste crash on android

@wesselvantilburg
Copy link

wesselvantilburg commented Apr 4, 2024

I believe you need a collapsable={false} on your viewRef to solve this on android for views outside viewport.
See https://shopify.github.io/react-native-skia/docs/snapshotviews/

return (
    <>
      <View ref={viewRef} style={{ position: 'absolute', left: screenWidth }} collapsable={false}>
        <View style={{ flexDirection: 'row' }}>
          <View style={{ flex: 1 }}>
            <Text>{`Name: ${data.name}`}</Text>
          </View>
          <View style={{ flex: 1, alignItems: 'flex-end' }}>
            <Text>{`Second Name: ${data.secondName}`}</Text>
          </View>
        </View>
        {imageSrc && <Image source={{ uri: imageSrc }} style={{ width, height }} onLoad={onLoad} />}
      </View>
      <Canvas ref={canvasRef} style={{ height, width, backgroundColor: 'white' }} onTouch={onTouch}>
        <Path path={activePath} style={'stroke'} strokeWidth={2} />
      </Canvas>
    </>
  );

@chiefchief
Copy link
Author

I believe you need a collapsable={false} on your viewRef to solve this on android for views outside viewport. See https://shopify.github.io/react-native-skia/docs/snapshotviews/

return (
    <>
      <View ref={viewRef} style={{ position: 'absolute', left: screenWidth }} collapsable={false}>
        <View style={{ flexDirection: 'row' }}>
          <View style={{ flex: 1 }}>
            <Text>{`Name: ${data.name}`}</Text>
          </View>
          <View style={{ flex: 1, alignItems: 'flex-end' }}>
            <Text>{`Second Name: ${data.secondName}`}</Text>
          </View>
        </View>
        {imageSrc && <Image source={{ uri: imageSrc }} style={{ width, height }} onLoad={onLoad} />}
      </View>
      <Canvas ref={canvasRef} style={{ height, width, backgroundColor: 'white' }} onTouch={onTouch}>
        <Path path={activePath} style={'stroke'} strokeWidth={2} />
      </Canvas>
    </>
  );

i tried but didn't help, also tried - removeClippedSubviews: false, the same result

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants