gre / gl-react

gl-react – React library to write and compose WebGL shaders

Home Page:https://gl-react-cookbook.surge.sh

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Question] what is this error?

jonatasfernandespimenta opened this issue · comments

Hey, I'm using Expo and I'm having the following error when running my Expo app on IOS (it works on android):

Possible Unhandled Promise Rejection (id: 2):
String {
  "0": "E",
  "1": "X",
  "10": "l",
  "11": "i",
  "12": "d",
  "13": " ",
  "14": "p",
  "15": "i",
  "16": "x",
  "17": "e",
  "18": "l",
  "19": " ",
  "2": "G",
  "20": "d",
  "21": "a",
  "22": "t",
  "23": "a",
  "24": " ",
  "25": "a",
  "26": "r",
  "27": "g",
  "28": "u",
  "29": "m",
  "3": "L",
  "30": "e",
  "31": "n",
  "32": "t",
  "33": " ",
  "34": "f",
  "35": "o",
  "36": "r",
  "37": " ",
  "38": "g",
  "39": "l",
  "4": ":",
  "40": ".",
  "41": "t",
  "42": "e",
  "43": "x",
  "44": "I",
  "45": "m",
  "46": "a",
  "47": "g",
  "48": "e",
  "49": "2",
  "5": " ",
  "50": "D",
  "51": "(",
  "52": ")",
  "53": "!",
  "6": "I",
  "7": "n",
  "8": "v",
  "9": "a",
}

My code:
Image.js

import React from 'react';
import rectCrop from 'rect-crop';
import rectClamp from 'rect-clamp';
import { Surface } from "gl-react-expo";
import { GLSL, Node, Shaders } from "gl-react";

const shaders = Shaders.create({
  image: {
    frag: GLSL`
      precision highp float;
      varying vec2 uv;
      uniform sampler2D t;
      uniform vec4 crop;
      vec2 invert (vec2 p) {${'' /* y is reversed in gl context */}
        return vec2(p.x, 1.0-p.y);
      }
      void main () {
        vec2 p = invert(invert(uv) * crop.zw + crop.xy);
        gl_FragColor =
          step(0.0, p.x) *
          step(0.0, p.y) *
          step(p.x, 1.0) *
          step(p.y, 1.0) *
          texture2D(t, p);
      }
    `,
  },
});

export default class Image extends React.PureComponent {
  render() {

    const { width, height, source, imageSize, resizeMode = 'cover', center, zoom } = this.props;

    if (!imageSize) {
      if (source.width && source.height) {
        imageSize = { width: source.width, height: source.height };
      } else {
        throw new Error(
          "gl-rect-image: imageSize is required if you don't provide {width,height} in source",
        );
      }
    }
    let crop;
    switch (resizeMode) {
      case 'cover': {
        if (!center) center = [0.5, 0.5];
        if (!zoom) zoom = 1;
        let rect = rectCrop(zoom, center)({ width, height }, imageSize);
        rect = rectClamp(rect, [0, 0, imageSize.width, imageSize.height]);
        crop = [
          rect[0] / imageSize.width,
          rect[1] / imageSize.height,
          rect[2] / imageSize.width,
          rect[3] / imageSize.height,
        ];

        break;
      }
      case 'contain': {
        if (center || zoom) {
          console.log(
            "gl-react-image: center and zoom props are only supported with resizeMode='cover'",
          );
        }
        const ratio = width / height;
        const imageRatio = imageSize.width / imageSize.height;
        crop =
          ratio > imageRatio
            ? [(1 - ratio / imageRatio) / 2, 0, ratio / imageRatio, 1]
            : [0, (1 - imageRatio / ratio) / 2, 1, imageRatio / ratio];
        break;
      }
      case 'stretch':
        if (center || zoom) {
          console.log(
            "gl-react-image: center and zoom props are only supported with resizeMode='cover'",
          );
        }
        crop = [0, 0, 1, 1];
        break;

      default:
        throw new Error('gl-react-image: unknown resizeMode=' + resizeMode);
    }

    return (
      <Node
      shader={shaders.image}
      uniforms={{
        t: { uri: source.uri },
        crop,
      }}
      />
    );
  }
}

ImageCrop

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { View, Image, PixelRatio, PanResponder } from 'react-native';
import { Surface } from 'gl-react-expo';
import GLImage from './Image';

const imageDimensionsAfterZoom = (viewport, dimensions, zoom) => {
  const ImageRatio = dimensions.width / dimensions.height;
  const ViewportRatio = viewport.width / viewport.height;
  if (ImageRatio > ViewportRatio) {
    return {
      height: Math.floor(viewport.height / zoom),
      width: Math.floor((viewport.height * ImageRatio) / zoom),
    };
  } else
    return {
      height: Math.floor(viewport.width / ImageRatio / zoom),
      width: Math.floor(viewport.width / zoom),
    };
};

const movementFromZoom = (gestureState, viewport, dimensions, offsets, zoom) => {
  let newPosX, newPosY;
  // X-axis
  let widthOffset = dimensions.width - viewport.width;
  let pxVsMovX = 1 / dimensions.width;
  let moveX = gestureState.dx * pxVsMovX * zoom;
  newPosX = parseFloat(offsets.x) - parseFloat(moveX);

  // Y-axis
  let heightOffset = dimensions.height - viewport.height;
  let pxVsMovY = 1 / dimensions.height;
  let moveY = gestureState.dy * pxVsMovY * zoom;
  newPosY = parseFloat(offsets.y) - parseFloat(moveY);
  return {
    x: newPosX,
    y: newPosY,
  };
};


class ImageCrop extends Component {
  constructor(props) {
    super(props);
    this.state = {
      zoom: 1,

      //pan settings
      centerX: 0.5,
      centerY: 0.5,

      //Image sizes
      imageHeight: 300,
      imageWidth: 300,
      imageDimHeight: 0,
      imageDimWidth: 0,
      currentCapture: '',
    };

    this.surfaceCont = React.createRef();
  }

  async captureSurface() {
    const pictureSave = await this.surfaceCont.current.glView.capture();
    return pictureSave;
  }

  UNSAFE_componentWillMount() {
    Image.getSize(this.props.image, (width, height) => {
      //update state
      this.setState({
        imageHeight: height,
        imageWidth: width,
      });
    });

    //
    //get dimensions after crop
    //
    this._dimensionAfterZoom = imageDimensionsAfterZoom(
      { height: this.props.cropHeight, width: this.props.cropWidth },
      { height: this.state.imageHeight, width: this.state.imageWidth },
      this.state.zoom,
    );

    this.setState({
      imageDimHeight: this._dimensionAfterZoom.height,
      imageDimWidth: this._dimensionAfterZoom.width,
    });

    this._panResponder = PanResponder.create({
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
      onPanResponderTerminationRequest: (evt, gestureState) => false,
      onShouldBlockNativeResponder: (evt, gestureState) => true,

      onPanResponderGrant: (evt, gestureState) => {
        //move variables
        this.offsetX = this.state.centerX;
        this.offsetY = this.state.centerY;

        //zoom variables
        this.zoomLastDistance = 0;
        this.zoomCurrentDistance = 0;
      },

      onPanResponderMove: (evt, gestureState) => {
        //We are moving the image
        if (evt.nativeEvent.changedTouches.length <= 1) {
          var trackX = (gestureState.dx / this.props.cropWidth) * this.state.zoom;
          var trackY = (gestureState.dy / this.props.cropHeight) * this.state.zoom;
          var newPosX = Number(this.offsetX) - Number(trackX);
          var newPosY = Number(this.offsetY) - Number(trackY);
          if (newPosX > 1) newPosX = Number(1);
          if (newPosY > 1) newPosY = Number(1);
          if (newPosX < 0) newPosX = Number(0);
          if (newPosY < 0) newPosY = Number(0);

          var movement = movementFromZoom(
            gestureState,
            { width: this.props.cropWidth, height: this.props.cropHeight },
            {
              width: this.state.imageDimWidth,
              height: this.state.imageDimHeight,
            },
            { x: this.offsetX, y: this.offsetY },
            this.state.zoom,
          );
          this.setState({ centerX: movement.x });
          this.setState({ centerY: movement.y });
        } else {
          //We are zooming the image
          if (this.zoomLastDistance == 0) {
            let a =
              evt.nativeEvent.changedTouches[0].locationX -
              evt.nativeEvent.changedTouches[1].locationX;
            let b =
              evt.nativeEvent.changedTouches[0].locationY -
              evt.nativeEvent.changedTouches[1].locationY;
            let c = Math.sqrt(a * a + b * b);
            this.zoomLastDistance = c.toFixed(1);
          } else {
            let a =
              evt.nativeEvent.changedTouches[0].locationX -
              evt.nativeEvent.changedTouches[1].locationX;
            let b =
              evt.nativeEvent.changedTouches[0].locationY -
              evt.nativeEvent.changedTouches[1].locationY;
            let c = Math.sqrt(a * a + b * b);
            this.zoomCurrentDistance = c.toFixed(1);

            //what is the zoom level
            var screenDiagonal = Math.sqrt(
              this.state.imageHeight * this.state.imageHeight +
                this.state.imageWidth * this.state.imageWidth,
            );
            var distance = (this.zoomCurrentDistance - this.zoomLastDistance) / 400;
            var zoom = this.state.zoom - distance;

            if (zoom < 0) zoom = 0.0000001;
            if (zoom > 1) zoom = 1;
            this.setState({
              zoom: zoom,
            });
            //Set last distance..
            this.zoomLastDistance = this.zoomCurrentDistance;
          }
        }
      },
    });
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (this.props.zoom != nextProps.zoom) {
      var zoom = (100 - nextProps.zoom) / 100;
      this.setState({ zoom: zoom });
    }

    //
    //get dimensions after crop
    //
    this._dimensionAfterZoom = imageDimensionsAfterZoom(
      { height: this.props.cropHeight, width: this.props.cropWidth },
      { height: this.state.imageHeight, width: this.state.imageWidth },
      this.state.zoom,
    );

    this.setState({
      imageDimHeight: this._dimensionAfterZoom.height,
      imageDimWidth: this._dimensionAfterZoom.width,
    });
  }
  render() {
    return (
      <View {...this._panResponder.panHandlers}>
        <Surface
          style={{ width: this.props.cropWidth, height: this.props.cropHeight }}
          pixelRatio={this.props.pixelRatio}
          backgroundColor="transparent"
          ref={this.surfaceCont}
        >
          <GLImage
            height={this.props.cropHeight}
            width={this.props.cropWidth}
            source={{ uri: this.props.image }}
            imageSize={{
              height: this.state.imageHeight,
              width: this.state.imageWidth,
            }}
            resizeMode="cover"
            zoom={this.state.zoom}
            center={[this.state.centerX, this.state.centerY]}
          />
        </Surface>
      </View>
    );
  }
  crop() {
    return this.surfaceCont.current.glView.capture({
      quality: this.props.quality,
      type: this.props.type,
      format: this.props.format,
      filePath: this.props.filePath,
    });
  }
}
ImageCrop.defaultProps = {
  image: '',
  cropWidth: 300,
  cropHeight: 300,
  zoomFactor: 0,
  minZoom: 0,
  maxZoom: 100,
  quality: 1,
  pixelRatio: PixelRatio.get(),
  type: 'jpg',
  format: 'base64',
  filePath: '',
};
ImageCrop.propTypes = {
  image: PropTypes.string.isRequired,
  cropWidth: PropTypes.number.isRequired,
  cropHeight: PropTypes.number.isRequired,
  zoomFactor: PropTypes.number,
  maxZoom: PropTypes.number,
  minZoom: PropTypes.number,
  quality: PropTypes.number,
  pixelRatio: PropTypes.number,
  type: PropTypes.string,
  format: PropTypes.string,
  filePath: PropTypes.string,
};

export default ImageCrop;

I really don't know what to do and I didn't find anything on internet :/

@gre @jonatasfernandespimenta I got this error when actually the url of the image is null or some empty string

I can't reproduce this (at least not in latest versions)

I tried to do

//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "../../gl-react-implementation";

const shaders = Shaders.create({
  DiamondCrop: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform sampler2D t;
void main() {
gl_FragColor = mix(
  texture2D(t, uv),
  vec4(0.0),
  step(0.5, abs(uv.x - 0.5) + abs(uv.y - 0.5))
);
}`,
  },
});

export const DiamondCrop = ({ children: t }) => (
  <Node shader={shaders.DiamondCrop} uniforms={{ t }} />
);

export default class Example extends Component {
  render() {
    const { width } = this.props;
    return (
      <Surface style={{ width, height: width }}>
        <DiamondCrop>{{ uri: "" }}</DiamondCrop>
      </Surface>
    );
  }
}

and it doesn't crash with this error. it renders white (as the uri is invalid) and it just have a warning about the wrong url.

Capture d’écran 2020-12-26 à 17 32 19

Capture d’écran 2020-12-26 à 17 32 22

any help on this is welcomed because I can't reproduce. (or need a very minimal example i can play with)