使用画布元素使用 javascript 调整图像大小
我很难理解如何在 JavaScript 中使用 canvas
元素.
I'm having a hard time to understand how to work with canvas
elements in JavaScript.
我正在实现一个调整大小的功能,用户可以在 lightbox
内调整图像大小.lightbox
将在单击预览图像后启动.在 lightbox
元素中,除了图像本身之外,还有宽度和高度两个输入字段.
I'm implementing a resize feature where user can resize image inside the lightbox
. The lightbox
will launch after preview image is been clicked. Inside the lightbox
element, in addition of the image itself, there are two input fields for width and height.
目标是生成base64
格式的原始图像的副本,并将其连同给定的宽度和高度作为查询参数发送到服务器,并让服务器端进行调整大小操作(我我的后端使用 PHP)或者更好,让 JavaScript 在前端进行调整大小操作并返回新的、调整大小的图像,准备通过 ajax
发送到服务器.
The objective is to generate a copy of the original image in base64
format and send it to the server along with given width and height as query parameters and let the server side do the resize operation (I'm using PHP for my back end) or even better, let JavaScript do the resize operation in the front end and return new, resized image ready to be sent to the server via ajax
.
问题是我不完全知道如何处理动态创建的 canvas
元素以及如何在前端使用它来调整图像大小.
The problem is that I don't exactly know how to deal with dynamically created canvas
elements and how can I use it to resize my image in the front end.
下面是我迄今为止尝试过但效果不佳的方法:
Underneath is what I've tried so far with poor results:
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']);
}
非常感谢任何提示、技巧和建议!
Any tips, tricks and advices are much appreciated !
推荐答案
您也可以在客户端调整图像大小.下面的示例代码使用从用户本地系统加载的图像来运行示例,而无需担心 CORS 问题.该片段还将图像存储为 Blob 对象,如果需要,可以将其发布到服务器.
You can resize an image also at the client-side. The example code below uses an image loaded from the user's local system, to run the example without need to worry about CORS issues. The snippet also stores the image as a Blob object, which can be posted to the server if needed.
// 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
属性包含图像的原始大小.
resizeImage
function creates a temporary canvas element, and calculates the dimensions for that canvas. Here the image is always shrinked, but you can implement your own resizing algorithms. img.naturalWidth/Height
properties contain the original size of the image.
当画布的大小设置正确时,图像被绘制到画布中,此时实际调整大小.然后画布返回给调用者,并分配给本地 canvas
变量.
When the size of the canvas has been correctly set, the image is drawn into the canvas, at this point the actual resizing happens. Then the canvas is returned to the caller, and assigned to the local canvas
variable.
然后从新创建的画布中创建一个 Blob 对象.toBlob
函数将回调函数、mime 类型和可选的质量参数(仅适用于 JPEG)作为参数.回调函数将画布附加到图像中,并将创建的 Blob 对象存储到 resizedImage
变量中以供进一步使用,最后移除临时画布元素.
Then a Blob object is created from the newly-created canvas. toBlob
function takes a callback function, mime-type and an optional quality parameter (for JPEGs only) as arguments. The callback function attaches the canvas into the image, and stores the created Blob object to resizedImage
variable for the further use, and finally removes the temporary canvas element.
好读于 MDN:
ctx.drawImage 方法
Blob 对象
Canvas.toBlob 方法
启用CORS的图片
如果您要将调整大小的图像发送到服务器,您可以创建一个 FormData 对象,并将图像附加到该对象.然后使用 AJAX 将对象发布到服务器.像这样的:
If you're going to send the resized image to the server, you can create a FormData object, and append the image to that object. Then post the object to the server with AJAX. Something like this:
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 对象在这种情况下)作为 xhr.send
调用的参数附加.
Notice, that the POST parameters (the FormData object in this case) are attached as an argument of xhr.send
call.
相关文章