解决方案
我正在尝试使用像素匹配库来比较两个图像的反应组件,我被困在输出图像上。outputCanvasRef总是null,所以在compareImages
函数中,它在outputCanvas.width = image1.width;
import { useRef, useState } from "react";
import pixelmatch from "pixelmatch";
const Tab1 = () => {
const [image1, setImage1] = useState(null);
const [image2, setImage2] = useState(null);
const [difference, setDifference] = useState(null);
const canvas1Ref = useRef(null);
const canvas2Ref = useRef(null);
const outputCanvasRef = useRef(null);
const handleFileChange = (setImage) => (event) => {
const file = event.target.files[0];
const fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = () => {
const image = new Image();
image.src = fileReader.result;
image.onload = () => setImage(image);
};
};
const compareImages = async () => {
if (image1 && image2) {
const canvas1 = canvas1Ref.current;
const canvas2 = canvas2Ref.current;
const outputCanvas = outputCanvasRef.current;
canvas1.width = image1.width;
canvas1.height = image1.height;
canvas2.width = image2.width;
canvas2.height = image2.height;
outputCanvas.width = image1.width;
outputCanvas.height = image1.height;
const ctx1 = canvas1.getContext("2d");
const ctx2 = canvas2.getContext("2d");
const outputCtx = outputCanvas.getContext("2d");
outputCtx.scale(0.5, 0.5);
ctx1.drawImage(image1, 0, 0);
ctx2.drawImage(image2, 0, 0);
const diff = pixelmatch(
ctx1.getImageData(0, 0, image1.width, image1.height),
ctx2.getImageData(0, 0, image2.width, image2.height),
null,
image1.width,
image1.height
);
outputCtx.putImageData(diff, 0, 0);
setDifference(outputCanvas);
}
};
return (
<div>
<input type="file" onChange={handleFileChange(setImage1)} />
<input type="file" onChange={handleFileChange(setImage2)} />
<button onClick={() => { compareImages() }}>Compare Images</button>
<canvas ref={canvas1Ref} />
<canvas ref={canvas2Ref} />
{difference && <canvas ref={outputCanvasRef} />}
</div>
);
}
export default Tab1;
可以使用像这样的扩展运算符{...props}
来传递一个条件ref
const itemProps = difference ? { ref: outputCanvasRef } : {};
<canvas {...itemProps} />
在你的实现中有几个地方出了问题:
- 您需要在没有任何条件的情况下渲染
output canvas
,以便它始终可用于比较功能。 pixelmatch
软件包要求您想要比较的图像始终具有相同的宽度&高度。要做到这一点,你可以使用宽度&两个图像1 &图2 .- 你需要将
getImageData
调用返回的数组缓冲区传递给pixelmatch
。getImageData
返回ImageData
对象。你可以像这样访问数组缓冲区ImageData.data
- 你应该传递
ImageData
对象的data
字段给pixelmatch
库的第三个参数作为参数,这样像素的差异就可以写在ImageData
对象中。
解决方案
import { useRef, useState } from "react";
import pixelmatch from "pixelmatch";
const Tab1 = () => {
const [image1, setImage1] = useState(null);
const [image2, setImage2] = useState(null);
const [difference, setDifference] = useState(null);
const canvas1Ref = useRef(null);
const canvas2Ref = useRef(null);
const outputCanvasRef = useRef(null);
const handleFileChange = (setImage) => (event) => {
const file = event.target.files[0];
const fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = () => {
const image = new Image();
image.src = fileReader.result;
image.onload = () => setImage(image);
};
};
const compareImages = async () => {
if (image1 && image2) {
const canvas1 = canvas1Ref.current;
const canvas2 = canvas2Ref.current;
const outputCanvas = outputCanvasRef.current;
canvas1.width = image1.width;
canvas1.height = image1.height;
canvas2.width = image1.width;
canvas2.height = image1.height;
outputCanvas.width = image1.width;
outputCanvas.height = image1.height;
const ctx1 = canvas1.getContext("2d");
const ctx2 = canvas2.getContext("2d");
const outputCtx = outputCanvas.getContext("2d");
const diff = outputCtx.createImageData(image1.width, image1.height);
ctx1.drawImage(image1, 0, 0);
ctx2.drawImage(image2, 0, 0);
pixelmatch(
ctx1.getImageData(0, 0, image1.width, image1.height).data,
ctx2.getImageData(0, 0, image1.width, image1.height).data,
diff.data,
image1.width,
image1.height
);
outputCtx.putImageData(diff, 0, 0);
setDifference(diff);
}
};
return (
<div>
<input type="file" onChange={handleFileChange(setImage1)} />
<input type="file" onChange={handleFileChange(setImage2)} />
<button onClick={() => { compareImages() }}>Compare Images</button>
<canvas ref={canvas1Ref} />
<canvas ref={canvas2Ref} />
{<canvas ref={outputCanvasRef} />}
</div>
);
}
export default Tab1;