前端实现图片裁剪功能,插件版和原生版

293 阅读3分钟

概要

最近遇到了一个需要用到图片裁剪功能,自己找了一些资料,有插件版和原生版的,VUE版本的我就不放了,原理类似,供大家参考。

插件版

Cropper.js 是一个用于裁剪图像的 JavaScript 插件。它可以让用户在浏览器中对图像进行裁剪和编辑操作,具体功能包括但不限于: 1.图像裁剪: 允许用户在预览中选择并裁剪图像的特定区域。 2.缩放和旋转: 支持用户对裁剪区域进行缩放和旋转操作,以便更精确地选择所需部分。 3.上传和导出: 提供了上传和导出裁剪后的图像功能,通常可以导出为Base64格式的图像数据或者Blob对象,以便于上传或保存到服务器。 4.交互式预览: 用户可以在裁剪过程中实时预览裁剪后的效果,可以调整裁剪框的大小和位置。 5.自定义选项: 支持各种自定义选项和配置,例如裁剪框的比例、裁剪框的最小和最大尺寸等,以满足不同场景的需求。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>图片裁剪</title>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.css"
    />
    <style>
      #image {
        max-width: 100%;
      }
    </style>
  </head>

  <body>
    <h1>图片裁剪</h1>
    <input type="file" id="fileInput" accept="image/*" />
    <div>
      <img id="image" src="" alt="选择图片" />
    </div>
    <button id="cropButton" style="display: none">裁剪图片</button>
    <div>
      <img id="croppedImage" src="" alt="裁剪后的图片" />
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
    <script>
      document
        .getElementById("fileInput")
        .addEventListener("change", function (event) {
          const file = event.target.files[0];
          if (file) {
            const reader = new FileReader();
            reader.onload = function (e) {
              const img = document.getElementById("image");
              img.src = e.target.result;
              img.onload = function () {
                const cropper = new Cropper(img, {
                  aspectRatio: 1 / 1, // 裁剪框的宽高比
                  viewMode: 1,
                  dragMode: "move",
                  autoCropArea: 0.8,
                  cropBoxMovable: true,
                  cropBoxResizable: true,
                  background: true,
                });

                document.getElementById("cropButton").style.display = "block";
                document.getElementById("cropButton").onclick = function () {
                  const canvas = cropper.getCroppedCanvas();
                  const base64Image = canvas.toDataURL("image/png");
                  // 处理裁剪后的图片,例如显示或上传
                  document.getElementById("croppedImage").src = base64Image;
                  console.log(base64Image);//输出裁剪后的图片base64编码
                };
              };
            };
            reader.readAsDataURL(file);
          }
        });
    </script>
  </body>
</html>

JS原生版(优化版)

原生版的就比较复杂一点,主要是用到了canvas和鼠标的一些事件

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片裁剪</title>
    <style>
        #canvas {
            border: 1px solid black;
            /* background-color: black; */
        }

        #croppedImage {
            display: none;
        }
    </style>
</head>

<body>
    <input type="file" id="fileInput" accept="image/*">
    <canvas id="canvas" width="500" height="500"></canvas>
    <button id="cropButton">裁剪</button>
    <img id="croppedImage" alt="裁剪后的图片">

    <script>
        const fileInput = document.getElementById('fileInput');
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const cropButton = document.getElementById('cropButton');
        const croppedImage = document.getElementById('croppedImage');

        let image = new Image();
        let cropStartX = 0;
        let cropStartY = 0;
        let cropEndX = 0;
        let cropEndY = 0;
        let isDrawing = false;
        let originalWidth = 0;
        let originalHeight = 0;
        let scale = 1;

        // 点击上传图片的时候
        fileInput.addEventListener('change', function (event) {
            const file = event.target.files[0];
            const reader = new FileReader();
            const maxWidth = 800; // 设置最大宽度
            const maxHeight = 600; // 设置最大高度
            // 文件读取完成后
            reader.onload = function (e) {
                image.src = e.target.result;

                image.onload = function () {
                    originalWidth = image.width;
                    originalHeight = image.height;

                    // 优化:如果图片尺寸超过最大值,进行缩放(防止图片过大溢出屏幕)
                    if (originalWidth > maxWidth || originalHeight > maxHeight) {
                        scale = Math.min(maxWidth / originalWidth, maxHeight / originalHeight);
                    }

                    const width = originalWidth * scale;
                    const height = originalHeight * scale;

                    canvas.width = width;
                    canvas.height = height;
                    ctx.drawImage(image, 0, 0, width, height);
                };
            };

            reader.readAsDataURL(file);
        });

        // 在图像上鼠标按下的时候
        canvas.addEventListener('mousedown', function (event) {
            cropStartX = event.offsetX;
            cropStartY = event.offsetY;
            isDrawing = true;
        });

        // 在图像上鼠标移动的时候
        canvas.addEventListener('mousemove', function (event) {
            if (isDrawing) {
                cropEndX = event.offsetX;
                cropEndY = event.offsetY;
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
                ctx.strokeStyle = 'red';
                ctx.strokeRect(cropStartX, cropStartY, cropEndX - cropStartX, cropEndY - cropStartY);
            }
        });

        // 在图像上松开鼠标的时候
        canvas.addEventListener('mouseup', function (event) {
            isDrawing = false;
        });

        // 点击裁剪的时候
        cropButton.addEventListener('click', function () {
            // 计算裁剪区域的宽度和高度
            const cropWidth = Math.abs(cropEndX - cropStartX);
            const cropHeight = Math.abs(cropEndY - cropStartY);
            // 计算裁剪区域的左上角坐标
            const cropX = Math.min(cropStartX, cropEndX);
            const cropY = Math.min(cropStartY, cropEndY);
            // 创建canvas 元素,并存放裁剪后的图像
            const croppedCanvas = document.createElement('canvas');
            croppedCanvas.width = cropWidth;
            croppedCanvas.height = cropHeight;
            const croppedCtx = croppedCanvas.getContext('2d');
            croppedCtx.drawImage(image, cropX / scale, cropY / scale, cropWidth / scale, cropHeight / scale, 0, 0, cropWidth, cropHeight);

            console.log(croppedCanvas.toDataURL());
            croppedImage.src = croppedCanvas.toDataURL();
            croppedImage.style.display = 'block';
        });
    </script>
</body>

</html>

小结

工作好累,想摸鱼。