react-easy-crop을 사용한 이미지 조작
이미지 조작에는 원하는 결과를 얻기 위해 다양한 방법과 기술을 사용하여 이미지를 변경하는 작업이 포함됩니다. 이를 통해 다른 부분은 무시하면서 이미지 측면에 집중할 수 있습니다. 결과적으로 이미지 종횡비, 형식 또는 크기가 줄어듭니다. 이미지 조작은 프런트 엔드 앱에서 중요한 역할을 합니다.
react-easy-crop 패키지는 무료 오픈 소스 JavaScript 라이브러리입니다. URL로 이미지 형식(JPEG, PNG 및 GIF) 또는 HTML5에서 지원되는 문자열 및 비디오 형식base64을 지원합니다. 프런트 엔드 앱에서 이미지/비디오를 조작하기 위한 효율적인 도구입니다.
이 기사에서는 react-easy-crop으로 이미지를 조작하는 데 중점을 둘 것입니다. 우리는 간단한 파일 업로드 애플리케이션을 만들 것입니다. 잘린 영역의 결과는 react-easy-crop에서 지원하는 다음 기능을 사용하여 표시됩니다.
React 앱 만들기
시작하려면 아래 명령을 사용하여 React 애플리케이션을 시작하십시오.
npx create-react-app easy-crop
cd easy-crop
npm i react-easy-crop
npm i @material-ui/core
npm start
시작하기 전에 수정
app.css
하여 일부 스타일을 응용 프로그램에 추가합니다. 아래 코드 블록을 복사하여 app.css
에 붙여넣습니다..App {
background-color: #c4c4c4;
font-family: 'Helvetica Neue', sans-serif;
}
.App-header {
padding-top: 20px;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
color: #fff;
}
label {
font-weight: bold;
padding-left: 10px;
}
button {
z-index: 2;
cursor: pointer;
width: 100%;
background-color: #000;
color: #fff;
padding: 10px 0;
}
.cropped-image {
height: 600px;
width: auto;
}
.cropped-image-container {
margin-top: 20px;
display: flex;
flex-direction: column;
}
._coverImage-holder {
padding: 25px 40px;
background-color:black;
border-radius: 5px;
cursor: pointer;
margin-bottom: 20px;
}
.container {
display: flex;
flex-direction: column;
position: relative;
}
.crop-container {
height: 600px;
width: 600px;
}
.controls {
display: flex;
flex-direction: column;
width: 600px;
position: absolute;
bottom: -15px;
}
react-easy-crop 설정
EasyCrop.js
라는 구성 요소를 만들고 아래 코드 블록을 붙여넣습니다.import React, { useState } from "react";
import Cropper from 'react-easy-crop';
const EasyCrop = () => {
const [crop, setCrop] = useState({ x: 0, y: 0 });
return (
<Cropper
image="https://cdn.pixabay.com/photo/2016/07/07/16/46/dice-1502706__340.jpg"
crop={crop}
onCropChange={setCrop}
/>
)
}
export default EasyCrop;
react-easy-crop이 지원하는 기능을 살펴보기 전에 아래 코드 블록으로
App.js
구성 요소를 업데이트하겠습니다.import EasyCrop from "./EasyCrop";
function App() {
return (
<div className="App">
<header className="App-header">
<EasyCrop />
</header>
</div>
);
}
export default App;
drag
기능은 기본적으로 활성화되어 있습니다. 앞으로 우리는 react-easy-crop이 제공하는 다른 기능을 구현할 것입니다.종횡비
종횡비는 이미지의 너비와 높이를 나타냅니다.
aspect
구성 요소에 Cropper
소품을 추가하여 조작할 수 있습니다.소품의 값 구문은
width/height
이고 기본값은 4/3
입니다.'Cropper' 구성 요소의 값을
5/5
로 수정합니다.<Cropper
image="https://cdn.pixabay.com/photo/2016/07/07/16/46/dice-1502706__340.jpg"
crop={crop}
aspect={5 / 5}
onCropChange={setCrop}
/>
자르기 모양
cropShape
소품을 추가하여 이미지 모양을 변경할 수 있습니다. 이 소품은 rect
또는 round
문자열을 허용합니다. 기본값은 rect
입니다. 이미지를 둥글게 만들기 위해 cropShape
값을 round
로 변경합니다.<Cropper
image="https://cdn.pixabay.com/photo/2016/07/07/16/46/dice-1502706__340.jpg"
crop={crop}
aspect={4 / 4}
cropShape="round"
onCropChange={setCrop}
/>
줌
확대/축소 기능을 활성화하기 위해 react-easy-crop은 5개의 소품을 제공합니다. 이러한 소품에는
zoom
, zoomWithScroll
, zoomSpeed
, minZoom
및 maxZoom
가 포함됩니다.import React, { useState } from "react";
import Slider from "@material-ui/core/Slider";
import Cropper from "react-easy-crop";
const EasyCrop = () => {
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
return (
<div>
<div className="crop-container">
<Cropper
image="https://cdn.pixabay.com/photo/2016/07/07/16/46/dice-1502706__340.jpg"
crop={crop}
zoom={zoom}
zoomSpeed={4}
maxZoom={3}
zoomWithScroll={true}
showGrid={true}
aspect={4 / 3}
onCropChange={setCrop}
onZoomChange={setZoom}
/>
</div>
<div className="controls">
<label>
Zoom
<Slider
value={zoom}
min={1}
max={3}
step={0.1}
aria-labelledby="zoom"
onChange={(e, zoom) => setZoom(zoom)}
className="range"
/>
</label>
</div>
</div>
);
};
export default EasyCrop;
회전
회전 기능은
rotation
및 onRotationChange
두 가지 소품을 사용하여 추가할 수 있습니다.import React, { useState } from "react";
import Slider from "@material-ui/core/Slider";
import Cropper from "react-easy-crop";
const EasyCrop = () => {
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
const [rotation, setRotation] = useState(0);
return (
<div>
<div className="crop-container">
<Cropper
image='https://cdn.pixabay.com/photo/2016/07/07/16/46/dice-1502706__340.jpg'
crop={crop}
rotation={rotation}
zoom={zoom}
zoomSpeed={4}
maxZoom={3}
zoomWithScroll={true}
showGrid={true}
aspect={4 / 3}
onCropChange={setCrop}
onZoomChange={setZoom}
onRotationChange={setRotation}
/>
</div>
<div className="controls">
<label>
Rotate
<Slider
value={rotation}
min={0}
max={360}
step={1}
aria-labelledby="rotate"
onChange={(e, rotation) => setRotation(rotation)}
className="range"
/>
</label>
</div>
</div>
);
};
export default EasyCrop;
오픈 소스 세션 재생
OpenReplay은 사용자가 웹 앱에서 수행하는 작업을 볼 수 있는 오픈 소스 세션 재생 제품군으로, 문제를 더 빨리 해결할 수 있도록 도와줍니다. OpenReplay는 데이터를 완벽하게 제어할 수 있도록 자체 호스팅됩니다.
디버깅 경험을 즐기십시오 - start using OpenReplay for free .
자른 이미지 표시
다음으로, react-easy-crop이 제공하는 지원 기능을 사용하여 애플리케이션에 파일 업로드 기능을 구현하여 동적으로 만들 것입니다. 이를 위해 먼저
Crop.js
라는 구성 요소를 생성하고 아래 코드 블록을 붙여넣습니다.export const createImage = (url) =>
new Promise((resolve, reject) => {
const image = new Image();
image.addEventListener("load", () => resolve(image));
image.addEventListener("error", (error) => reject(error));
image.setAttribute("crossOrigin", "anonymous");
image.src = url;
});
export function getRadianAngle(degreeValue) {
return (degreeValue * Math.PI) / 180;
}
export function rotateSize(width, height, rotation) {
const rotRad = getRadianAngle(rotation);
return {
width:
Math.abs(Math.cos(rotRad) * width) + Math.abs(Math.sin(rotRad) * height),
height:
Math.abs(Math.sin(rotRad) * width) + Math.abs(Math.cos(rotRad) * height),
};
}
export default async function getCroppedImg(
imageSrc,
pixelCrop,
rotation = 0,
flip = { horizontal: false, vertical: false }
) {
const image = await createImage(imageSrc);
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) {
return null;
}
const rotRad = getRadianAngle(rotation);
const { width: bBoxWidth, height: bBoxHeight } = rotateSize(
image.width,
image.height,
rotation
);
// set canvas size to match the bounding box
canvas.width = bBoxWidth;
canvas.height = bBoxHeight;
ctx.translate(bBoxWidth / 2, bBoxHeight / 2);
ctx.rotate(rotRad);
ctx.scale(flip.horizontal ? -1 : 1, flip.vertical ? -1 : 1);
ctx.translate(-image.width / 2, -image.height / 2);
ctx.drawImage(image, 0, 0);
const data = ctx.getImageData(
pixelCrop.x,
pixelCrop.y,
pixelCrop.width,
pixelCrop.height
);
canvas.width = pixelCrop.width;
canvas.height = pixelCrop.height;
ctx.putImageData(data, 0, 0);
return new Promise((resolve, reject) => {
canvas.toBlob((file) => {
resolve(URL.createObjectURL(file));
}, "image/jpeg");
});
}
후속 단계에서는
EasyCrop.js
구성 요소를 수정하여 이미지 소품을 동적으로 만듭니다.import { useCallback, useState } from "react";
import Slider from "@material-ui/core/Slider";
import Cropper from "react-easy-crop";
import getCroppedImg from "./Crop";
const EasyCrop = ({ image }) => {
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
const [rotation, setRotation] = useState(0);
const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
const [croppedImage, setCroppedImage] = useState(null);
const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
setCroppedAreaPixels(croppedAreaPixels);
}, []);
const showCroppedImage = useCallback(async () => {
try {
const croppedImage = await getCroppedImg(
image,
croppedAreaPixels,
rotation
);
console.log("donee", { croppedImage });
setCroppedImage(croppedImage);
} catch (e) {
console.error(e);
}
}, [croppedAreaPixels, rotation, image]);
const onClose = useCallback(() => {
setCroppedImage(null);
}, []);
return (
<div>
<button
style={{
display: image === null || croppedImage !== null ? "none" : "block",
}}
onClick={showCroppedImage}
>
Crop
</button>
<div
className="container"
style={{
display: image === null || croppedImage !== null ? "none" : "block",
}}
>
<div className="crop-container">
<Cropper
image={image}
crop={crop}
rotation={rotation}
zoom={zoom}
zoomSpeed={4}
maxZoom={3}
zoomWithScroll={true}
showGrid={true}
aspect={4 / 3}
onCropChange={setCrop}
onCropComplete={onCropComplete}
onZoomChange={setZoom}
onRotationChange={setRotation}
/>
</div>
<div className="controls">
<label>
Rotate
<Slider
value={rotation}
min={0}
max={360}
step={1}
aria-labelledby="rotate"
onChange={(e, rotation) => setRotation(rotation)}
className="range"
/>
</label>
<label>
Zoom
<Slider
value={zoom}
min={1}
max={3}
step={0.1}
aria-labelledby="zoom"
onChange={(e, zoom) => setZoom(zoom)}
className="range"
/>
</label>
</div>
</div>
<div className="cropped-image-container">
{croppedImage && (
<img className="cropped-image" src={croppedImage} alt="cropped" />
)}
{croppedImage && <button onClick={onClose}>close</button>}
</div>
</div>
);
};
export default EasyCrop;
또한 파일 업로드 기능을 포함하여
App.js
구성 요소를 최종적으로 변경합니다.import React, { useState } from "react";
import EasyCrop from "./EasyCrop";
function App() {
const [image, setImage] = useState(null);
const handleImageUpload = async (e) => {
setImage(URL.createObjectURL(e.target.files[0]));
};
return (
<div className="App">
<header className="App-header">
<label className="_coverImage-holder">
Upload Image
<input
type="file"
name="cover"
onChange={handleImageUpload}
accept="img/*"
style={{ display: "none" }}
/>
</label>
<EasyCrop image={image} />
</header>
</div>
);
}
export default App;
결론
React-easy-crop은 React 애플리케이션에서 이미지를 조작하는 데 효율적입니다. 웹용 이미지를 변경할 때 원하는 결과를 얻을 수 있는 유연성을 제공합니다. 다음은 source code 및 live app에 대한 링크입니다.
A TIP FROM THE EDITOR: On the topic of working with images, our React 18 - What's New and How it Will Benefit Developers article highlights some advantages of the latest version of React.
Reference
이 문제에 관하여(react-easy-crop을 사용한 이미지 조작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/asayerio_techblog/image-manipulation-with-react-easy-crop-1008텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)