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

2023-06-21前端开发问题
14

本文介绍了使用画布元素使用 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.

这篇关于使用画布元素使用 javascript 调整图像大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

The End

相关推荐

js删除数组中指定元素的5种方法
在JavaScript中,我们有多种方法可以删除数组中的指定元素。以下给出了5种常见的方法并提供了相应的代码示例: 1.使用splice()方法: let array = [0, 1, 2, 3, 4, 5];let index = array.indexOf(2);if (index -1) { array.splice(index, 1);}// array = [0,...
2024-11-22 前端开发问题
182

JavaScript小数运算出现多位的解决办法
在开发JS过程中,会经常遇到两个小数相运算的情况,但是运算结果却与预期不同,调试一下发现计算结果竟然有那么长一串尾巴。如下图所示: 产生原因: JavaScript对小数运算会先转成二进制,运算完毕再转回十进制,过程中会有丢失,不过不是所有的小数间运算会...
2024-10-18 前端开发问题
301

JavaScript(js)文件字符串中丢失"\"斜线的解决方法
问题描述: 在javascript中引用js代码,然后导致反斜杠丢失,发现字符串中的所有\信息丢失。比如在js中引用input type=text onkeyup=value=value.replace(/[^\d]/g,) ,结果导致正则表达式中的\丢失。 问题原因: 该字符串含有\,javascript对字符串进行了转...
2024-10-17 前端开发问题
437

layui中table列表 增加属性 edit="date",不生效怎么办?
如果你想在 layui 的 table 列表中增加 edit=date 属性但不生效,可能是以下问题导致的: 1. 缺少日期组件的初始化 如果想在表格中使用日期组件,需要在页面中引入 layui 的日期组件,并初始化: script type="text/javascript" src="/layui/layui.js"/scrip...
2024-06-11 前端开发问题
455

Rails/Javascript:如何将 rails 变量注入(非常)简单的 javascript
Rails/Javascript: How to inject rails variables into (very) simple javascript(Rails/Javascript:如何将 rails 变量注入(非常)简单的 javascript)...
2024-04-20 前端开发问题
5

CoffeeScript 总是以匿名函数返回
CoffeeScript always returns in anonymous function(CoffeeScript 总是以匿名函数返回)...
2024-04-20 前端开发问题
13