前端都能用canvas操作图片做些什么实际的事情

学习地址: https://www.bilibili.com/video/BV1vu4y1f7Sq/?spm_id_from=333.999.0.0&vd_source=9f9e93fdd48179f56492874d4af8ba44

1. 上传图片前压缩

  思路 

    1  创建 FileReader 对象  使用 readAsDataURL  读取文件

    2  在 FileReader onload 结束后 再进行后续处理

    3  FileReader的result 就是图片的base64地址

    4  创建一个canvas 使用 canvas.drawImage 把图片绘制出来

    5  使用.toBlob 将 canvas 元素 转换成blob 图片 并压缩

import React, { useState, useRef } from "react";

const Jiancai = () => {
  const [imageSrc, setImageSrc] = useState<string | undefined>(undefined);
  const [imageSrcYs, setImageSrcYs] = useState<string | undefined>(undefined);
  const imgRef = useRef<HTMLImageElement>(null);
  // 在 input 元素的 onChange 事件中,e 是 React 的 ChangeEvent 类型,且目标是 HTMLInputElement
  // 因此可以将 fileChange 函数的参数类型修改为 React.ChangeEvent<HTMLInputElement>
  const fileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    let file: File = e.target.files![0];
    // 创建 FileReader 对象
    let fr: FileReader = new FileReader();
    // 创建 FileReader 读取文件
    fr.readAsDataURL(file);
    fr.onload = () => {
      if (fr.result) setImageSrc(fr.result as string);
      // 等待图片加载完成后再处理
      if (imgRef.current) {
        imgRef.current.onload = () => {
          let pressCanvas = document.createElement("canvas");
          pressCanvas.width = imgRef.current!.width;
          pressCanvas.height = imgRef.current!.height;

          let ctx = pressCanvas.getContext("2d");
          // drawImage
          ctx?.drawImage(
            imgRef.current!,
            0,
            0,
            pressCanvas.width,
            pressCanvas.height
          );
          // toBlob, toDataURL 通过参数压缩
          // 用canvas 真实dom 转blob
          // toBlob 有三个参数,回调函数,图片格式,质量0-1
          console.log("?????");
          pressCanvas.toBlob(
            (blob) => {
              const blobUrl = URL.createObjectURL(blob!);
              setImageSrcYs(blobUrl);
            },
            "image/jpeg",
            0.5
          );
        };
      }
    };
  };

  return (
    <div>
      <p>压缩</p>
      <input
        type="file"
        onChange={(e) => {
          fileChange(e);
        }}
      />
      <img ref={imgRef} src={imageSrc} alt="" />
      <h2>压缩后</h2>
      <img src={imageSrcYs} alt="" />
    </div>
  );
};
export default Jiancai;

 

2. 对页面进行截图

import { useRef } from "react";
import html2canvas from "html2canvas";
import "./index.css";
const Jietu = () => {
  // 确定截图目标

  // 如果是图片DOM canvasDom 或者videoDom
  // 直接用 canvas ctx.drawImage() 绘制图片
  // 然后接着 toDataURL 或者 toBlob  =》 然后保存到本地(file-saver) 或者上传服务器

  // 如果是 div 或者 document.body
  // html2canvas 库

  // div 截图功能
  const screenshotRef = useRef<HTMLImageElement>(null);
  const screenShotDiv = () => {
    if (screenshotRef.current) {
      html2canvas(screenshotRef.current, {
        useCORS: true, // 允许加载跨域图片
        scale: window.devicePixelRatio > 1 ? window.devicePixelRatio : 2, // 提高清晰度
        backgroundColor: "#ffffff", // 设置背景颜色
      }).then((canvas) => {
        // 将 canvas 转换为图片数据 URL
        const imageData = canvas.toDataURL("image/png");

        // 创建下载链接
        const link = document.createElement("a");
        link.href = imageData;
        link.download = "screenshot.png"; // 设置下载文件名

        // 触发下载
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
      }).catch((error) => {
        console.error('截图失败:', error);
      });
    }
  };

  return (
    <div>
      <h2>截图</h2>
      <button
        onClick={() => {
          screenShotDiv();
        }}
      >
        截图
      </button>
      <div className="test-box" ref={screenshotRef}>
        <div className="box-item">1</div>
        <div className="box-item">2</div>
        <div className="box-item">3</div>
        <div className="box-item">4</div>
        <div className="box-item">5</div>
        <div className="box-item">6</div>
        <div className="box-item">7</div>
        <div className="box-item">8</div>
        <div className="box-item">9</div>
      </div>
    </div>
  );
};
export default Jietu;

 

3. 滤镜

import React, { useState, useRef } from "react";

const Lvjing = () => {
  const [imageSrc, setImageSrc] = useState<string | undefined>(undefined);
  const imgRef = useRef<HTMLImageElement>(null);
  const divRef = useRef<HTMLDivElement>(null);
  // 在 input 元素的 onChange 事件中,e 是 React 的 ChangeEvent 类型,且目标是 HTMLInputElement
  // 因此可以将 fileChange 函数的参数类型修改为 React.ChangeEvent<HTMLInputElement>
  const fileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    let file: File = e.target.files![0];
    // 预览 file-base64
    // 创建 FileReader 对象
    let fr: FileReader = new FileReader();
    // 创建 FileReader 读取文件
    fr.readAsDataURL(file);
    fr.onload = () => {
      if (fr.result) setImageSrc(fr.result as string);
    };
  };

  const addFilter = () => {
    // drawImage 画到canvas上面
    let filterCanvas = document.createElement("canvas");
    if(imgRef.current) {
        filterCanvas.width = imgRef.current.width;
        filterCanvas.height = imgRef.current.height;
        let ctx = filterCanvas.getContext("2d");
        ctx?.drawImage(imgRef.current!, 0, 0, filterCanvas.width, filterCanvas.height);
        // getImageData 获取某一个canvas区域内所有的像素点
        let imageData = ctx!.getImageData(0, 0, filterCanvas.width, filterCanvas.height);
        console.log(imageData);
        let imageDataLength = imageData.data.length;
        // 遍历每一个像素点
        // 每四个一组 RGBA
        // 可以对像素点惊醒处理
        for(let i = 0; i < imageDataLength; i+=4) {
            if(i % 2 === 0) {
                imageData.data[i+2] = 0;
            }
        }
        // 清空canvas
        ctx?.clearRect(0, 0, imgRef.current.width, imgRef.current.height);
        // putImageData 重新绘制到canvas
        ctx?.putImageData(imageData, 0, 0);
        // 添加到页面上
        divRef.current!.appendChild(filterCanvas)
    }
    
  };
  return (
    <div>
      
      <input
        type="file"
        onChange={(e) => {
          fileChange(e);
        }}
      />
      <img ref={imgRef} src={imageSrc} alt="" />
      <button
        onClick={() => {
          addFilter();
        }}
      >
        添加滤镜
      </button>
      <div ref={ divRef }></div>
    </div>
  );
};
export default Lvjing;

 

4. 剪裁图片

posted on 2025-09-07 22:07  贲风  阅读(12)  评论(0)    收藏  举报