expo-image-cropper-gl-react
Version:
Crop image in Expo using pan to move, pinch to zoom -> capture to file or base64
96 lines (88 loc) • 2.52 kB
JavaScript
import React from 'react';
import rectCrop from 'rect-crop';
import rectClamp from 'rect-clamp';
import { Shaders, Node } from 'gl-react';
const shaders = Shaders.create({
image: {
frag: `
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.warn(
"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.warn(
"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,
}}
/>
);
}
}