javascript - 使用 Canvas 元素通过 JavaScript 调整图像大小

标签 javascript image canvas html5-canvas

我很难理解如何在 JavaScript 中使用 canvas 元素。

我正在实现一个调整大小功能,用户可以在lightbox内调整图像大小。单击预览图像后,lightbox 将启动。在 lightbox 元素内部,除了图像本身之外,还有两个宽度和高度输入字段。

目标是生成base64格式的原始图像的副本,并将其连同给定的宽度和高度作为查询参数发送到服务器,并让服务器端执行调整大小操作(我我的后端使用 PHP),或者更好的是,让 JavaScript 在前端执行调整大小操作,并返回新的、调整大小的图像,准备通过 ajax 发送到服务器。

问题是我不完全知道如何处理动态创建的 canvas 元素以及如何使用它在前端调整图像大小。

下面是我迄今为止尝试过的但效果不佳的方法:

index.html (省略基本HTML元素和灯箱效果)

<!-- input fields for width and height -->
<div class="container">
    <div class="form-inline">
        <div class="form-group">
            <input type="number" class="form-control" id="width" placeholder="px">
        </div>
        <div class="form-group">
            <input type="number" class="form-control" id="height" placeholder="px">
        </div>
        <button id="resize" type="button" class="btn btn-primary">Resize</button>
    </div>
</div>

<!-- preview image -->
<div class="container">
    <img src="img/img1.jpg" alt="" class="img-responsive" id="preview">
</div>

<script type="text/javascript">
    button = document.getElementById("resize");

    button.addEventListener("click", function() {
        // get image
        const image = document.getElementById('preview');

        // create a canvas element
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext("2d");

        canvas.width = image.width; // destination canvas size
        canvas.height = canvas.width * image.height / image.width;

        ctx.drawImage(image, 0, 0, image.width, image.height);
        var canvasData = canvas.toDataURL("image/jpeg");


        // ajax call
        var xhr = new XMLHttpRequest();
        var params = "photo=" + encodeURIComponent(canvasData) + "&name=" + encodeURIComponent(name) + "&width="+ encodeURIComponent(width) + "&height=" + encodeURIComponent(height);
        // send request
        xhr.open("POST", "admin.php?" + params);
        xhr.send();
    });
</script>

admin.php (这里没什么特别的,只是解码图像并将其写入文件夹)

<?php

if(isset($_POST['photoUpload']) && isset($_POST['name'])) {
// decode base64 formatted image
$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $_POST['photoUpload']));

if(isset($_POST['width'] && $_POST['height'])) {
    // resize image here using imagemagick
}

// write file to "img" directory
file_put_contents(dataPath.'img/'.$_POST['name'], $data);

// done
exit('OK|'.dataPath.'img/'.$_POST['name']);
}

非常感谢任何提示、技巧和建议!

最佳答案

您也可以在客户端调整图像大小。下面的示例代码使用从用户本地系统加载的图像来运行示例,而无需担心 CORS 问题。该代码片段还将图像存储为 Blob 对象,如果需要,可以将其发布到服务器。

// Creates a canvas containing a resized image
function resizeImage(img) {
  var canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d'),
    oWidth = img.naturalWidth,
    oHeight = img.naturalHeight,
    ratio = oWidth / oHeight,
    width = (ratio > 1) ? Math.min(200, oWidth) : Math.min(100, oWidth),
    height = Math.round(width / ratio);
  canvas.width = width;
  canvas.height = height;
  canvas.className = 'temp-cnv';
  document.body.appendChild(canvas);
  ctx.drawImage(img, 0, 0, width, height);
  return canvas;
}

// Define UI elements
var img = document.getElementById('img'),
  loadBut = document.getElementById('load'),
  resizeBut = document.getElementById('resize'),
  resizedImage; // This will be sent to the server

// Creates a blob and attaches it to an image element
resizeBut.addEventListener('click', function() {
  var canvas;
  if (img.src === 'https://stacksnippets.net/js') {
    return; // Quit, no image loaded
  }
  canvas = resizeImage(img);
  canvas.toBlob(function(blob) {
    img.src = URL.createObjectURL(blob);
    resizedImage = blob;
    canvas.parentElement.removeChild(canvas);
  }, 'image/jpeg', 0.99);
});

// Reads an image from the user's local system
loadBut.addEventListener('change', function(e) {
  var file = new FileReader();
  file.addEventListener('load', function() {
    img.src = file.result;
  });
  file.readAsDataURL(e.target.files[0]);
});
.temp-cnv {
  display: none;
}
<input type="file" id="load">
<button id="resize">Resize</button>
<br>
<img src="" id="img">

resizeImage 函数创建一个临时 Canvas 元素,并计算该 Canvas 的尺寸。这里图像总是缩小的,但您可以实现自己的调整大小算法。 img.naturalWidth/Height 属性包含图像的原始大小。

当 Canvas 的大小正确设置后,图像将被绘制到 Canvas 中,此时会发生实际的大小调整。然后 Canvas 返回给调用者,并分配给本地 canvas 变量。

然后从新创建的 Canvas 中创建一个 Blob 对象。 toBlob 函数采用回调函数、mime 类型和可选的质量参数(仅适用于 JPEG)作为参数。回调函数将 Canvas 附加到图像中,并将创建的 Blob 对象存储到 resizedImage 变量中以供进一步使用,最后删除临时 Canvas 元素。

值得在 MDN 上阅读:

ctx.drawImage method
Blob object
Canvas.toBlob method
CORS enabled images

如果您要将调整大小的图像发送到服务器,您可以创建一个 FormData 对象,并将图像附加到该对象。然后使用 AJAX 将对象发布到服务器。像这样的事情:

var xhr = new XMLHttpRequest(),
    form = new FormData();
form.append('imageBlob', resizedImage); // resizedImage is the Blob object created in the first snippet
form.append('imageName', 'THE_NAME_OF_THE_IMAGE');
xhr.addEventListener('load', function (data) {
    // AJAX response handler code
});
xhr.open('POST', 'THE_URL_TO_POST_TO');
xhr.send(form);

请注意,POST 参数(本例中为 FormData object)作为 xhr.send 调用的参数附加。

关于javascript - 使用 Canvas 元素通过 JavaScript 调整图像大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53506593/

相关文章:

php - 如何在不同的分辨率下使用猫头鹰轮播显示不同的图像? WordPress的

javascript - 如何跟踪在 JavaScript Canvas 上按下某个键的时间?

javascript - 在 Canvas 中填充奇偶 react

javascript - 使用 javascript 或正则表达式从值中分割数字和字符串

javascript - onMousedown 与 onClick 的缺点?

javascript - Jinja2 中的 {% now 'U' %} 实现?

javascript - 如何从原始图像创建缩略图而不失真?

javascript - 如何确保我的 Javascript 动画保持在其他固定元素下方?

javascript - 如何使用map函数在第一个react组件中添加图像并忽略其余组件

javascript - canvas 和 body 元素的奇怪光标行为