使用画布元素使用JavaScript调整图像大小

时间:2018-11-27 19:12:18

标签: javascript image canvas html5-canvas

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

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

目标是生成base64格式的原始图像的副本,并将其与给定的宽度和高度一起作为查询参数发送到服务器,并让服务器端执行调整大小操作(我正在使用PHP(对于我的后端,则是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']);
}

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

1 个答案:

答案 0 :(得分:2)

您也可以在客户端调整图像的大小。下面的示例代码使用从用户本地系统加载的图像来运行该示例,而无需担心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函数创建一个临时画布元素,并计算该画布的尺寸。在这里,映像始终会缩小,但是您可以实现自己的调整大小算法。 img.naturalWidth/Height属性包含图像的原始大小。

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

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

可以在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调用的参数附加。