简体   繁体   English

useRef 总是以 null 的形式返回,并且无法获取图像比较中的当前值

[英]useRef always coming back as null and is not able to get .current value in image comparison

I am trying to make a react component to compare two images using the pixel match library and I am stuck on the output image.我正在尝试制作一个反应组件来使用像素匹配库比较两个图像,但我卡在了 output 图像上。 The outputCanvasRef is always null so in the compareImages function it errors on the line with outputCanvas.width = image1.width; outputCanvasRef 始终为 null,因此在compareImages function 中,它在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;

Can use the spread operator like this {...props} to pass a conditional ref可以使用像这样的扩展运算符{...props}来传递条件引用

  const itemProps = difference ? { ref: outputCanvasRef } : {};

  <canvas {...itemProps} />

There are several things that went wrong in your implementation:您的实施中有几处错误:

  • You need to render the output canvas without any condition so that it is always available for use in the comparison function.您需要无条件渲染output canvas ,以便它始终可用于比较 function。
  • the pixelmatch package requires that the images you want to compare always have the same width & height. pixelmatch package 要求您要比较的图像始终具有相同的宽度和高度。 To do this, you can use the width & height of the first image for both image 1 & image 2 canvas.为此,您可以将第一张图片的宽度和高度用于图片 1 和图片 2 canvas。
  • You need to pass the array buffer that is returned from getImageData call to the pixelmatch .您需要将从getImageData调用返回的数组缓冲区传递给pixelmatch The getImageData returns ImageData object. You can access the array buffer like this ImageData.data getImageData返回ImageData object。您可以像这样访问数组缓冲区ImageData.data
  • You should pass an ImageData object's data field to the pixelmatch library's third parameter as argument so that the difference in pixels can be written in the ImageData object.您应该将ImageData对象的data字段作为参数传递给pixelmatch库的第三个参数,以便可以将像素差异写入ImageData object。

Solution解决方案



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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM