gl-react
gl-react copied to clipboard
[Question] what is this error?
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.


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