前端都能用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. 剪裁图片
浙公网安备 33010602011771号