首页 > 解决方案 > 如何通过放大和缩小来修改图像?

问题描述

我有一个类似画廊的组件,重要的部分是:

       

     <Gallery>
      <Header>
        <img src={galleryIcon} alt='Galley icon' />
        <h1>My Gallery</h1>
      </Header>
      <Images isImage={custom.length > 0}>
        {custom.length > 0 &&
          custom.map((c, i) => (
            <img
              id={`custom${i}`}
              key={`custom${i}`}
              src={c.img}
              alt='brick'
              onClick={() => (setEdit((prev) => !prev), setActual(c))}
            />
          ))}
        <div className='add'>
          <button onClick={() => setGallery((prev) => !prev)}>
            <img src={add} alt='Add icon' />
          </button>
          <p>Click to add a brick from our collections!</p>
        </div>
      </Images>
    </Gallery>

每个图像都有这种风格:

img {
    box-sizing: border-box;
    height: 28vh;
    width: 28vh;
    margin-right: 1.5rem;
    cursor: pointer;
  }

此外,一旦用户输入新图像,我会使用以下功能调整大小以不破坏比例:

export function resizeImage(
  file: File | Blob,
  maxWidth: number,
  maxHeight: number,
  scale = 1
): Promise<Blob> {
  return new Promise<Blob>((fulfill, reject) => {
    const image = new Image();

    image.src = URL.createObjectURL(file);

    image.onload = () => {
      URL.revokeObjectURL(image.src);

      const width = image.width;
      const height = image.height;

      if (width <= maxWidth && height <= maxHeight) {
        fulfill(file);
      }

      let newWidth = 0;
      let newHeight = 0;

      if (scale !== 1) {
        newWidth = (width * scale) / maxWidth;
        newHeight = (height * scale) / maxHeight;
      } else if (width > height) {
        newHeight = height * (maxWidth / width);
        newWidth = maxWidth;
      } else {
        newWidth = width * (maxHeight / height);
        newHeight = maxHeight;
      }

      console.log(newWidth, newHeight);

      const canvas = document.createElement('canvas');
      canvas.width = newWidth;
      canvas.height = newHeight;

      const context = canvas.getContext('2d');

      context?.drawImage(image, 0, 0, newWidth, newHeight);

      canvas.toBlob((blob) => blob && fulfill(blob), file.type);
    };

    image.onerror = reject;
  });
}

最后,调整大小组件:

const Resize: React.FC<Props> = ({ actual, setResize, setCustom, custom }) => {
  let stats: Stats = {} as Stats;

  const getStats = useCallback((): Stats => stats, []);

  const updateStats = useCallback(
    (newStats: Stats): Stats => (stats = newStats),
    []
  );

  const getResizedCustom = useCallback(
    async (copy: Custom): Promise<Custom> => {
      const actualWidth = window.innerWidth;
      const actualHeight = window.innerHeight;

      const maxWidth = actualWidth < 1152 ? 180 : 360;
      const maxHeight = actualHeight < 800 ? 180 : 360;

      const newBlob = await resizeImage(
        copy.blob,
        maxWidth,
        maxHeight,
        getStats().scale
      );

      return {
        blob: newBlob,
        img: URL.createObjectURL(newBlob),
        id: copy.id,
        type: 'custom',
        price: copy.price,
        amount: copy.amount,
      };
    },
    [stats]
  );

  const updateActual = useCallback(async () => {
    // remove actual
    const newCustomArr = [...custom];
    const customCopy = newCustomArr.splice(newCustomArr.indexOf(actual), 1)[0];

    const newCustom = await getResizedCustom(customCopy);

    console.log(customCopy);
    console.log(newCustom);
    setCustom([...newCustomArr, newCustom]);
  }, [actual, custom, setCustom, getResizedCustom]);

  return (
    <Container>
      <Header>
        <h1>ADJUST YOUR BRICK</h1>
        <img
          src={close}
          alt='close icon'
          onClick={() => setResize((prev) => !prev)}
        />
      </Header>
      <Main>
        <h2>Pinch and zoom</h2>
        <TransformWrapper onZoomChange={updateStats}>
          <TransformComponent>
            <img src={actual.img} alt='brick' />
          </TransformComponent>
        </TransformWrapper>
        <button
          onClick={async () => (
            await updateActual(), setResize((prev) => !prev)
          )}
        >
          DONE
        </button>
      </Main>
    </Container>
  );
};

我还使用react-zoom-pan-pinch来放大和缩小图像。我的问题是:如何根据 TransformWrapper 组件的 onZoomChange 函数提供的比例调整 DOM 上的图像大小?那可能吗?有一种更好且不那么“hacky”的方法可以根据缩放比例在 DOM 上调整图像的大小?

我会尽快提供最低限度的回购,但现在,这里是完整的回购:https ://github.com/Mdsp9070/brickart/tree/dev

标签: javascriptcssreactjstypescript

解决方案


这肯定是可能的,但是您需要将更多道具传递给drawImage. 查看文档。它还有四个您没有使用的可选参数。如果您只使用前四个,则包括整个图像。当使用所有八个道具时,前四个是指要使用原始图像的哪个部分(裁剪),而接下来的四个指定将图像选择放在画布上的哪个位置。

您需要进行一些数学运算和一些事件跟踪,以根据缩放中心和比例计算源矩形。


推荐阅读