react-native-image-cropper
Version:
Crop image in React Native using pan to move, pinch to zoom -> capture to file or base64
107 lines (102 loc) • 2.53 kB
JavaScript
import GL from "gl-react";
import React from "react";
import rectCrop from "rect-crop";
import rectClamp from "rect-clamp";
import PropTypes from 'prop-types';
const shaders = GL.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);
}`
}
});
const Image = GL.createComponent(
({
width,
height,
source,
imageSize,
resizeMode = "cover",
center,
zoom,
}) => {
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 <GL.Node
shader={shaders.image}
uniforms={{
t: source,
crop,
}}
/>;
},
{
displayName: "Image",
propTypes: {
source: PropTypes.any.isRequired,
imageSize: PropTypes.shape({
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
}),
resizeMode: PropTypes.string,
}
});
module.exports ={
Image,
}