旋转图像后,画布无法旋转,只能将图像旋转并适合原始画布的高度和宽度

问题描述 投票:0回答:1

我希望画布的高度和宽度在旋转图像时发生变化并相应地工作,并且叠加层也应适合旋转的画布,并且裁剪应相应地工作。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Image Cropper</title>
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <style>
    html,
    body {
      background: black;
      margin: 0;
      padding: 0;
      height: 90%;
    }
    
    .image-container {
      position: relative;
      min-height: 80%;
      display: flex;
      align-items: center;
      justify-content: center;
      margin: auto;
      overflow: visible;
      /* background-color: #f8f9fa; */
    }
    /* @media (max-width: 480px) {
            .image-container {
                min-height: 60vh;
            }
        } */
    
    #canvas {
      display: block;
      max-width: 100%;
      max-height: 100%;
      margin: auto;
      /* background-color: white; */
    }
    
    .main-div {
      padding-top: 5%;
      width: 100%;
      height: 100%;
      background: black;
    }
    
    .overlay {
      position: absolute;
      border: 2px solid yellow;
      cursor: move;
      touch-action: none;
      z-index: 1;
    }
    
    .ui-resizable-handle {
      background-image: none;
    }
    
    .corner {
      position: absolute;
      width: 15px;
      height: 15px;
      background-color: yellow;
      border-radius: 50%;
    }
    
    .corner.top-left {
      top: -5px;
      left: -5px;
    }
    
    .corner.top-right {
      top: -5px;
      right: -5px;
    }
    
    .corner.bottom-left {
      bottom: -5px;
      left: -5px;
    }
    
    .corner.bottom-right {
      bottom: -5px;
      right: -5px;
    }
    
    .overlay-background {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5);
      /* Default opacity for rectangle */
      pointer-events: none;
    }
    
    .rotate-buttons {
      margin-top: 10px;
    }
  </style>
</head>

<body>
  <div class="main-div">
    <button id="cropButton">Crop</button>
    <select id="shapeSelect" onchange="selectShape()">
      <option value="rectangle" selected>Rectangle</option>
      <option value="circle">Circle</option>
    </select>
    <div class="rotate-buttons">
      <button onclick="rotateClockwise()">Rotate Clockwise</button>
      <button onclick="rotateCounterClockwise()">Rotate Counter Clockwise</button>
    </div>
    <div class="image-container">
      <div class="overlay-background"></div>
      <canvas id="canvas"></canvas>
      <div class="overlay">
        <div class="corner top-left"></div>
        <div class="corner top-right"></div>
        <div class="corner bottom-left"></div>
        <div class="corner bottom-right"></div>
      </div>
    </div>
    <div id="croppedImagePreview"></div>
  </div>

  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script>
  <!-- Include Touch Punch for touch support -->
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      const imageObj = new Image();
      const overlay = document.querySelector('.overlay');
      const overlayBackground = document.querySelector('.overlay-background');
      const croppedCanvas = document.createElement("canvas");
      const croppedCtx = croppedCanvas.getContext("2d");
      let selectedShape = "rectangle";
      let rotation = 0; // Initial rotation angle

      // Define selectShape function to fix the Uncaught ReferenceError
      window.selectShape = function() {
        selectedShape = document.getElementById("shapeSelect").value;
        console.log(selectedShape);
        // Adjust overlay style based on selected shape
        overlay.style.borderRadius = selectedShape === "circle" ? "50%" : "0%"; // Adjust border radius for circle
        // Adjust overlay background opacity based on selected shape
        if (selectedShape === "circle") {
          overlayBackground.style.backgroundColor = "rgba(0, 0, 0, 0.5)"; // 50% opacity for circle
        } else {
          overlayBackground.style.backgroundColor = "rgba(0, 0, 0, 0.7)"; // Higher opacity for rectangle
        }
      };

      // Function to rotate the image clockwise
      window.rotateClockwise = function() {
        rotation += 90;
        drawRotatedImage();
      };

      // Function to rotate the image counter-clockwise
      window.rotateCounterClockwise = function() {
        rotation -= 90;
        drawRotatedImage();
      };

      function drawRotatedImage() {
        const originalWidth = imageObj.naturalWidth;
        const originalHeight = imageObj.naturalHeight;
        const is90Or270 = Math.abs(rotation % 360) === 90 || Math.abs(rotation % 360) === 270;

        // Set canvas size based on rotation
        if (is90Or270) {
          canvas.width = originalHeight;
          canvas.height = originalWidth;
        } else {
          canvas.width = originalWidth;
          canvas.height = originalHeight;
        }

        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.save();
        ctx.translate(canvas.width / 2, canvas.height / 2);
        ctx.rotate(rotation * Math.PI / 180);
        ctx.drawImage(imageObj, -originalWidth / 2, -originalHeight / 2, originalWidth, originalHeight);
        ctx.restore();

        // Update the overlay to match the new dimensions
        initializeOverlay();
      }

      imageObj.onload = function() {
        const container = document.querySelector('.image-container');
        const ratio = Math.min(container.clientWidth / imageObj.naturalWidth, container.clientHeight / imageObj.naturalHeight);
        const imageWidth = imageObj.naturalWidth * ratio;
        const imageHeight = imageObj.naturalHeight * ratio;

        canvas.width = imageObj.naturalWidth;
        canvas.height = imageObj.naturalHeight;
        canvas.style.width = `${imageWidth}px`;
        canvas.style.height = `${imageHeight}px`;


        container.style.width = `${imageWidth}px`;
        container.style.height = `${imageHeight}px`;

        ctx.drawImage(imageObj, 0, 0, imageObj.naturalWidth, imageObj.naturalHeight);
        initializeOverlay();
      };

      imageObj.crossOrigin = "Anonymous";
      imageObj.src = 'rope41.png'; // Make sure the path is correct

      function initializeOverlay() {
        const container = document.querySelector('.image-container');
        const ratio = Math.min(container.clientWidth / imageObj.naturalWidth, container.clientHeight / imageObj.naturalHeight);
        const imageWidth = imageObj.naturalWidth * ratio;
        const imageHeight = imageObj.naturalHeight * ratio;
        var tempImageWidth = imageWidth - 4; //Adjusting width the initial overlay to fit properly in pixels
        var tempImageHeight = imageHeight - 3; //Adjusting height the initial overlay to fit properly pixels

        overlay.style.width = `${tempImageWidth}px`;
        overlay.style.height = `${tempImageHeight}px`;
        // Center the overlay
        overlay.style.top = `${(container.clientHeight - imageHeight) / 2}px`;
        overlay.style.left = `${(container.clientWidth - imageWidth) / 2}px`;

        $(overlay).resizable({
          containment: "parent",
          handles: 'n, e, s, w, ne, se, sw, nw',
          minWidth: 100, // Setting minimum width for resizing
          minHeight: 100, // Setting minimum height for resizing
          resize: function(event, ui) {
            updateOverlayBackground(ui.position, ui.size);
          }
        }).draggable({
          containment: "parent",
          drag: function(event, ui) {
            // Get the current dimensions using jQuery
            const currentWidth = $(overlay).width();
            const currentHeight = $(overlay).height();
            // Create a size object to pass to the update function
            const size = {
              width: currentWidth,
              height: currentHeight
            };
            updateOverlayBackground(ui.position, size);
          }
        });

        updateOverlayBackground({
          top: overlay.style.top,
          left: overlay.style.left
        }, {
          width: tempImageWidth,
          height: tempImageHeight
        });
      }

      function updateOverlayBackground(position, size) {
        // Corrected to ensure position and size are correctly parsed as numbers
        const left = parseFloat(position.left) || 0; // Added default value to prevent undefined
        const top = parseFloat(position.top) || 0; // Added default value to prevent undefined
        const width = parseFloat(size.width) || 0; // Added default value to prevent undefined
        const height = parseFloat(size.height) || 0; // Added default value to prevent undefined

        overlayBackground.style.clipPath = `polygon(
                    0 0, 
                    0 100%, 
                    ${left}px 100%, 
                    ${left}px ${top}px, 
                    ${left + width}px ${top}px, 
                    ${left + width}px ${top + height}px, 
                    ${left}px ${top + height}px, 
                    ${left}px 100%, 
                    100% 100%, 
                    100% 0
                )`;
      }

      document.getElementById('cropButton').addEventListener('click', cropImage);

      function cropImage() {
        const selectedShape = document.getElementById("shapeSelect").value;
        const canvasRect = canvas.getBoundingClientRect();
        const bounds = overlay.getBoundingClientRect();

        const scaleX = canvas.width / canvasRect.width;
        const scaleY = canvas.height / canvasRect.height;

        const cropX = (bounds.left - canvasRect.left) * scaleX;
        const cropY = (bounds.top - canvasRect.top) * scaleY;
        const cropWidth = bounds.width * scaleX;
        const cropHeight = bounds.height * scaleY;

        croppedCanvas.width = cropWidth;
        croppedCanvas.height = cropHeight;

        if (selectedShape === "rectangle") {
          croppedCtx.drawImage(canvas, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
        } else if (selectedShape === "circle") {
          let rx = cropWidth / 2; // Radius along x-axis
          let ry = cropHeight / 2; // Radius along y-axis
          let cx = rx; // Center along x-axis
          let cy = ry; // Center along y-axis

          croppedCtx.save(); // Save the current context state
          croppedCtx.beginPath();
          croppedCtx.translate(cx, cy); // Translate to the center of the ellipse
          croppedCtx.scale(1, ry / rx); // Scale to make the circle an ellipse
          croppedCtx.arc(0, 0, rx, 0, Math.PI * 2);
          croppedCtx.closePath();
          croppedCtx.restore(); // Restore the previous context state
          croppedCtx.clip();

          croppedCtx.drawImage(
            canvas,
            cropX,
            cropY,
            cropWidth,
            cropHeight,
            0,
            0,
            cropWidth,
            cropHeight
          );
        }

        const imgPreview = document.getElementById('croppedImagePreview');
        imgPreview.innerHTML = '';
        const img = new Image();
        img.src = croppedCanvas.toDataURL("image/png");
        console.log(img.src);
        imgPreview.appendChild(img);
      }
    });
  </script>
</body>

</html>

旋转时,我需要画布也旋转,并在旋转的图像上进行裁剪。 我尝试根据旋转切换画布的高度和宽度,但没有成功。

javascript html css crop
1个回答
0
投票

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Image Cropper</title>
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <style>
    html,
    body {
      background: black;
      margin: 0;
      padding: 0;
      height: 90%;
    }
    
    .image-container {
      position: relative;
      min-height: 80%;
      display: flex;
      align-items: center;
      justify-content: center;
      margin: auto;
      overflow: visible;
      /* background-color: #f8f9fa; */
    }
    /* @media (max-width: 480px) {
            .image-container {
                min-height: 60vh;
            }
        } */
    
    #canvas {
      display: block;
      max-width: 100%;
      max-height: 100%;
      margin: auto;
      /* background-color: white; */
    }
    
    .main-div {
      padding-top: 5%;
      width: 100%;
      height: 100%;
      background: black;
    }
    
    .overlay {
      position: absolute;
      border: 2px solid yellow;
      cursor: move;
      touch-action: none;
      z-index: 1;
    }
    
    .ui-resizable-handle {
      background-image: none;
    }
    
    .corner {
      position: absolute;
      width: 15px;
      height: 15px;
      background-color: yellow;
      border-radius: 50%;
    }
    
    .corner.top-left {
      top: -5px;
      left: -5px;
    }
    
    .corner.top-right {
      top: -5px;
      right: -5px;
    }
    
    .corner.bottom-left {
      bottom: -5px;
      left: -5px;
    }
    
    .corner.bottom-right {
      bottom: -5px;
      right: -5px;
    }
    
    .overlay-background {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5);
      /* Default opacity for rectangle */
      pointer-events: none;
    }
    
    .rotate-buttons {
      margin-top: 10px;
    }
  </style>
</head>

<body>
  <div class="main-div">
    <button id="cropButton">Crop</button>
    <select id="shapeSelect" onchange="selectShape()">
      <option value="rectangle" selected>Rectangle</option>
      <option value="circle">Circle</option>
    </select>
    <div class="rotate-buttons">
      <button onclick="rotateClockwise()">Rotate Clockwise</button>
      <button onclick="rotateCounterClockwise()">Rotate Counter Clockwise</button>
    </div>
    <div class="image-container">
      <div class="overlay-background"></div>
      <canvas id="canvas"></canvas>
      <div class="overlay">
        <div class="corner top-left"></div>
        <div class="corner top-right"></div>
        <div class="corner bottom-left"></div>
        <div class="corner bottom-right"></div>
      </div>
    </div>
    <div id="croppedImagePreview"></div>
  </div>

  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script>
  <!-- Include Touch Punch for touch support -->
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      const imageObj = new Image();
      const overlay = document.querySelector('.overlay');
      const overlayBackground = document.querySelector('.overlay-background');
      const croppedCanvas = document.createElement("canvas");
      const croppedCtx = croppedCanvas.getContext("2d");
      let selectedShape = "rectangle";
      let rotation = 0; // Initial rotation angle

      // Define selectShape function to fix the Uncaught ReferenceError
      window.selectShape = function() {
        selectedShape = document.getElementById("shapeSelect").value;
        console.log(selectedShape);
        // Adjust overlay style based on selected shape
        overlay.style.borderRadius = selectedShape === "circle" ? "50%" : "0%"; // Adjust border radius for circle
        // Adjust overlay background opacity based on selected shape
        if (selectedShape === "circle") {
          overlayBackground.style.backgroundColor = "rgba(0, 0, 0, 0.5)"; // 50% opacity for circle
        } else {
          overlayBackground.style.backgroundColor = "rgba(0, 0, 0, 0.7)"; // Higher opacity for rectangle
        }
      };

      // Function to rotate the image clockwise
      window.rotateClockwise = function() {
        rotation += 90;
        drawRotatedImage();
      };

      // Function to rotate the image counter-clockwise
      window.rotateCounterClockwise = function() {
        rotation -= 90;
        drawRotatedImage();
      };

      function drawRotatedImage() {
        const originalWidth = imageObj.naturalWidth;
        const originalHeight = imageObj.naturalHeight;
        const is90Or270 = Math.abs(rotation % 360) === 90 || Math.abs(rotation % 360) === 270;

        // Set canvas size based on rotation
        if (is90Or270) {
          canvas.width = originalHeight;
          canvas.height = originalWidth;
        } else {
          canvas.width = originalWidth;
          canvas.height = originalHeight;
        }

        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.save();
        ctx.translate(canvas.width / 2, canvas.height / 2);
        ctx.rotate(rotation * Math.PI / 180);
        ctx.drawImage(imageObj, -originalWidth / 2, -originalHeight / 2, originalWidth, originalHeight);
        ctx.restore();

        // Update the overlay to match the new dimensions
        initializeOverlay();
      }

      imageObj.onload = function() {
        const container = document.querySelector('.image-container');
        const ratio = Math.min(container.clientWidth / imageObj.naturalWidth, container.clientHeight / imageObj.naturalHeight);
        const imageWidth = imageObj.naturalWidth * ratio;
        const imageHeight = imageObj.naturalHeight * ratio;

        canvas.width = imageObj.naturalWidth;
        canvas.height = imageObj.naturalHeight;
        canvas.style.width = `${imageWidth}px`;
        canvas.style.height = `${imageHeight}px`;


        container.style.width = `${imageWidth}px`;
        container.style.height = `${imageHeight}px`;

        ctx.drawImage(imageObj, 0, 0, imageObj.naturalWidth, imageObj.naturalHeight);
        initializeOverlay();
      };

      imageObj.crossOrigin = "Anonymous";
      imageObj.src = 'rope41.png'; // Make sure the path is correct

      function initializeOverlay() {
        const container = document.querySelector('.image-container');
        const ratio = Math.min(container.clientWidth / imageObj.naturalWidth, container.clientHeight / imageObj.naturalHeight);
        const imageWidth = imageObj.naturalWidth * ratio;
        const imageHeight = imageObj.naturalHeight * ratio;
        var tempImageWidth = imageWidth - 4; //Adjusting width the initial overlay to fit properly in pixels
        var tempImageHeight = imageHeight - 3; //Adjusting height the initial overlay to fit properly pixels

        overlay.style.width = `${tempImageWidth}px`;
        overlay.style.height = `${tempImageHeight}px`;
        // Center the overlay
        overlay.style.top = `${(container.clientHeight - imageHeight) / 2}px`;
        overlay.style.left = `${(container.clientWidth - imageWidth) / 2}px`;

        $(overlay).resizable({
          containment: "parent",
          handles: 'n, e, s, w, ne, se, sw, nw',
          minWidth: 100, // Setting minimum width for resizing
          minHeight: 100, // Setting minimum height for resizing
          resize: function(event, ui) {
            updateOverlayBackground(ui.position, ui.size);
          }
        }).draggable({
          containment: "parent",
          drag: function(event, ui) {
            // Get the current dimensions using jQuery
            const currentWidth = $(overlay).width();
            const currentHeight = $(overlay).height();
            // Create a size object to pass to the update function
            const size = {
              width: currentWidth,
              height: currentHeight
            };
            updateOverlayBackground(ui.position, size);
          }
        });

        updateOverlayBackground({
          top: overlay.style.top,
          left: overlay.style.left
        }, {
          width: tempImageWidth,
          height: tempImageHeight
        });
      }

      function updateOverlayBackground(position, size) {
        // Corrected to ensure position and size are correctly parsed as numbers
        const left = parseFloat(position.left) || 0; // Added default value to prevent undefined
        const top = parseFloat(position.top) || 0; // Added default value to prevent undefined
        const width = parseFloat(size.width) || 0; // Added default value to prevent undefined
        const height = parseFloat(size.height) || 0; // Added default value to prevent undefined

        overlayBackground.style.clipPath = `polygon(
                    0 0, 
                    0 100%, 
                    ${left}px 100%, 
                    ${left}px ${top}px, 
                    ${left + width}px ${top}px, 
                    ${left + width}px ${top + height}px, 
                    ${left}px ${top + height}px, 
                    ${left}px 100%, 
                    100% 100%, 
                    100% 0
                )`;
      }

      document.getElementById('cropButton').addEventListener('click', cropImage);

      function cropImage() {
        const selectedShape = document.getElementById("shapeSelect").value;
        const canvasRect = canvas.getBoundingClientRect();
        const bounds = overlay.getBoundingClientRect();

        const scaleX = canvas.width / canvasRect.width;
        const scaleY = canvas.height / canvasRect.height;

        const cropX = (bounds.left - canvasRect.left) * scaleX;
        const cropY = (bounds.top - canvasRect.top) * scaleY;
        const cropWidth = bounds.width * scaleX;
        const cropHeight = bounds.height * scaleY;

        croppedCanvas.width = cropWidth;
        croppedCanvas.height = cropHeight;

        if (selectedShape === "rectangle") {
          croppedCtx.drawImage(canvas, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
        } else if (selectedShape === "circle") {
          let rx = cropWidth / 2; // Radius along x-axis
          let ry = cropHeight / 2; // Radius along y-axis
          let cx = rx; // Center along x-axis
          let cy = ry; // Center along y-axis

          croppedCtx.save(); // Save the current context state
          croppedCtx.beginPath();
          croppedCtx.translate(cx, cy); // Translate to the center of the ellipse
          croppedCtx.scale(1, ry / rx); // Scale to make the circle an ellipse
          croppedCtx.arc(0, 0, rx, 0, Math.PI * 2);
          croppedCtx.closePath();
          croppedCtx.restore(); // Restore the previous context state
          croppedCtx.clip();

          croppedCtx.drawImage(
            canvas,
            cropX,
            cropY,
            cropWidth,
            cropHeight,
            0,
            0,
            cropWidth,
            cropHeight
          );
        }

        const imgPreview = document.getElementById('croppedImagePreview');
        imgPreview.innerHTML = '';
        const img = new Image();
        img.src = croppedCanvas.toDataURL("image/png");
        console.log(img.src);
        imgPreview.appendChild(img);
      }
    });
  </script>
</body>

</html>

© www.soinside.com 2019 - 2024. All rights reserved.