Konva에서 자르기 사각형 외부의 불투명도 변경
Nov 21 2020
React와 konva로 이미지 자르기 도구를 만들려고합니다. 나머지 이미지를 흐리게하기 위해 자르기 사각형 외부의 불투명도를 변경하고 싶습니다.
지금까지 직사각형과 이미지에 다른 불투명도를 설정하려고 시도했지만 실패했습니다. 나는 고개를 들었고 이것을하는 직접적인 방법이 없다
이 답변 의 도움으로 반응하도록 조정 한 자르기 기능은 다음과 같습니다.
import React, { useState, useEffect, useRef } from "react";
import { render } from "react-dom";
import { Stage, Layer, Rect, Image } from "react-konva";
import Konva from "konva";
const App = () => {
// Stage dims
let sW = 720,
sH = 720,
sX = 0,
sY = 0;
let src = "https://dummyimage.com/720x720/e85de8/fff&text=SO Rocks!";
let img = document.createElement("img");
useEffect(() => {
img.src = src;
function loadStatus() {
setloading(false);
}
img.addEventListener("load", loadStatus);
return () => {
img.removeEventListener("load", loadStatus);
};
}, [img, src]);
let scale = 1;
const [loading, setloading] = useState(true);
const [posStart, setposStart] = useState({});
const [posNow, setposNow] = useState({});
const [mode, setmode] = useState("");
/**
* Sets the state of posStart and posNow for tracking the coordinates of the cropping rectangle
* @param {Object} posIn - Coordinates of the pointer when MouseDown is fired
*/
function startDrag(posIn) {
setposStart({ x: posIn.x, y: posIn.y });
setposNow({ x: posIn.x, y: posIn.y });
}
/**
* Updates the state accordingly when the MouseMove event is fired
* @param {Object} posIn - Coordiantes of the current position of the pointer
*/
function updateDrag(posIn) {
setposNow({ x: posIn.x, y: posIn.y });
let posRect = reverse(posStart, posNow);
r2.current.x(posRect.x1);
r2.current.y(posRect.y1);
r2.current.width(posRect.x2 - posRect.x1);
r2.current.height(posRect.y2 - posRect.y1);
r2.current.visible(true);
}
/**
* Reverse coordinates if dragged left or up
* @param {Object} r1 - Coordinates of the starting position of cropping rectangle
* @param {Object} r2 - Coordinates of the current position of cropping rectangle
*/
function reverse(r1, r2) {
let r1x = r1.x,
r1y = r1.y,
r2x = r2.x,
r2y = r2.y,
d;
if (r1x > r2x) {
d = Math.abs(r1x - r2x);
r1x = r2x;
r2x = r1x + d;
}
if (r1y > r2y) {
d = Math.abs(r1y - r2y);
r1y = r2y;
r2y = r1y + d;
}
return { x1: r1x, y1: r1y, x2: r2x, y2: r2y }; // return the corrected rect.
}
/**
* Crops the image and saves it in jpeg format
* @param {Konva.Rect} r - Ref of the cropping rectangle
*/
function setCrop(r) {
let jpeg = new Konva.Image({
image: img,
x: sX,
y: sY
});
jpeg.cropX(r.x());
jpeg.cropY(r.y());
jpeg.cropWidth(r.width() * scale);
jpeg.cropHeight(r.height() * scale);
jpeg.width(r.width());
jpeg.height(r.height());
const url = jpeg.toDataURL({ mimeType: "image/jpeg", quality: "1.0" });
const a = document.createElement("a");
a.href = url;
a.download = "cropped.jpg";
a.click();
}
// Foreground rect to capture events
const r1 = useRef();
// Cropping rect
const r2 = useRef();
const image = useRef();
return (
<div className="container">
<Stage width={sW} height={sH}>
<Layer>
{!loading && (
<Image
ref={image}
{...{
image: img,
x: sX,
y: sY
}}
/>
)}
<Rect
ref={r1}
{...{
x: 0,
y: 0,
width: sW,
height: sH,
fill: "white",
opacity: 0
}}
onMouseDown={function (e) {
setmode("drawing");
startDrag({ x: e.evt.layerX, y: e.evt.layerY });
}}
onMouseMove={function (e) {
if (mode === "drawing") {
updateDrag({ x: e.evt.layerX, y: e.evt.layerY });
image.current.opacity(0.5);
r2.current.opacity(1);
}
}}
onMouseUp={function (e) {
setmode("");
r2.current.visible(false);
setCrop(r2.current);
image.current.opacity(1);
}}
/>
<Rect
ref={r2}
listening={false}
{...{
x: 0,
y: 0,
width: 0,
height: 0,
stroke: "white",
dash: [5, 5]
}}
/>
</Layer>
</Stage>
</div>
);
};
render(<App />, document.getElementById("root"));
위 코드의 데모
답변
2 mplusr Nov 21 2020 at 14:04
Konva.Group 및 클립 속성을 사용하여 수행 할 수 있습니다. 새 Konva.Image를 그룹에 추가하고 자르기 사각형과 동일하게 자르기 위치와 크기를 설정합니다. 그룹의 청취 소품을 false로 설정하는 것을 잊지 마십시오. 그렇지 않으면 상황이 복잡해집니다. 최종 결과는 다음과 같습니다.
import { render } from "react-dom";
import React, { useLayoutEffect, useRef, useState } from "react";
import { Stage, Layer, Image, Rect, Group } from "react-konva";
/**
* Crops a portion of image in Konva stage and saves it in jpeg format
* @param {*} props - Takes no props
*/
function Cropper(props) {
// Stage dims
let sW = 720,
sH = 720,
sX = 0,
sY = 0;
let src = "https://dummyimage.com/720x720/e85de8/fff&text=SO Rocks!";
let img = new window.Image();
useLayoutEffect(() => {
img.src = src;
function loadStatus() {
// img.crossOrigin = "Anonymous";
setloading(false);
}
img.addEventListener("load", loadStatus);
return () => {
img.removeEventListener("load", loadStatus);
};
}, [img, src]);
let i = new Konva.Image({
x: 0,
y: 0,
width: 0,
height: 0
});
let scale = 1;
const [loading, setloading] = useState(true);
const [posStart, setposStart] = useState({});
const [posNow, setposNow] = useState({});
const [mode, setmode] = useState("");
/**
* Sets the state of posStart and posNow for tracking the coordinates of the cropping rectangle
* @param {Object} posIn - Coordinates of the pointer when MouseDown is fired
*/
function startDrag(posIn) {
setposStart({ x: posIn.x, y: posIn.y });
setposNow({ x: posIn.x, y: posIn.y });
}
/**
* Updates the state accordingly when the MouseMove event is fired
* @param {Object} posIn - Coordiantes of the current position of the pointer
*/
function updateDrag(posIn) {
setposNow({ x: posIn.x, y: posIn.y });
let posRect = reverse(posStart, posNow);
r2.current.x(posRect.x1);
r2.current.y(posRect.y1);
r2.current.width(posRect.x2 - posRect.x1);
r2.current.height(posRect.y2 - posRect.y1);
r2.current.visible(true);
grp.current.clip({
x: posRect.x1,
y: posRect.y1,
width: posRect.x2 - posRect.x1,
height: posRect.y2 - posRect.y1
});
grp.current.add(i);
i.image(img);
i.width(img.width);
i.height(img.height);
i.opacity(1);
}
/**
* Reverse coordinates if dragged left or up
* @param {Object} r1 - Coordinates of the starting position of cropping rectangle
* @param {Object} r2 - Coordinates of the current position of cropping rectangle
*/
function reverse(r1, r2) {
let r1x = r1.x,
r1y = r1.y,
r2x = r2.x,
r2y = r2.y,
d;
if (r1x > r2x) {
d = Math.abs(r1x - r2x);
r1x = r2x;
r2x = r1x + d;
}
if (r1y > r2y) {
d = Math.abs(r1y - r2y);
r1y = r2y;
r2y = r1y + d;
}
return { x1: r1x, y1: r1y, x2: r2x, y2: r2y }; // return the corrected rect.
}
/**
* Crops the image and saves it in jpeg format
* @param {Konva.Rect} r - Ref of the cropping rectangle
*/
function setCrop(r) {
let jpeg = new Konva.Image({
image: img,
x: sX,
y: sY
});
jpeg.cropX(r.x());
jpeg.cropY(r.y());
jpeg.cropWidth(r.width() * scale);
jpeg.cropHeight(r.height() * scale);
jpeg.width(r.width());
jpeg.height(r.height());
const url = jpeg.toDataURL({ mimeType: "image/jpeg", quality: "1.0" });
const a = document.createElement("a");
a.href = url;
a.download = "cropped.jpg";
a.click();
}
// Foreground rect to capture events
const r1 = useRef();
// Cropping rect
const r2 = useRef();
const image = useRef();
const grp = useRef();
return (
<div className="container">
<Stage width={sW} height={sH}>
<Layer>
{!loading && (
<Image
ref={image}
listening={false}
{...{
image: img,
x: sX,
y: sY
}}
/>
)}
<Rect
ref={r1}
{...{
x: 0,
y: 0,
width: sW,
height: sH,
fill: "white",
opacity: 0
}}
onMouseDown={function (e) {
setmode("drawing");
startDrag({ x: e.evt.layerX, y: e.evt.layerY });
image.current.opacity(0.2);
}}
onMouseMove={function (e) {
if (mode === "drawing") {
updateDrag({ x: e.evt.layerX, y: e.evt.layerY });
}
}}
onMouseUp={function (e) {
setmode("");
r2.current.visible(false);
setCrop(r2.current);
image.current.opacity(1);
grp.current.removeChildren(i);
}}
/>
<Group listening={false} ref={grp}></Group>
<Rect
ref={r2}
listening={false}
{...{
x: 0,
y: 0,
width: 0,
height: 0,
stroke: "white",
dash: [5, 10]
}}
/>
</Layer>
</Stage>
</div>
);
}
render(<Cropper />, document.getElementById("root"));
모든 귀중한 입력에 대해 @Vanquished Wombat 에게 감사드립니다 . 이것은 여기 에 그의 대답의 적응입니다 .
위 코드의 데모