如何将图片上传到HTML5画布中

81

我目前正在使用http://paperjs.org创建一个HTML5画布绘图应用程序。我想让用户将图片上传到画布中。我知道我需要制作登录和注册,但是否有更简单的方法?我看过HTML5拖放上传。

5个回答

168

我猜你的意思是要把图像加载到画布上,而不是从画布上传图像。

最好先阅读一下他们在这里提供的所有有关画布的文章: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Using_images

但基本上你需要做的就是在 JavaScript 中创建一个图像,并将图像的 src 属性设置为文件位置。如果要从用户那里加载图像,则需要使用文件系统 API。

这里提供了一个简短的示例:http://jsfiddle.net/influenztial/qy7h5/

function handleImage(e){
    var reader = new FileReader();
    reader.onload = function(event){
        var img = new Image();
        img.onload = function(){
            canvas.width = img.width;
            canvas.height = img.height;
            ctx.drawImage(img,0,0);
        }
        img.src = event.target.result;
    }
    reader.readAsDataURL(e.target.files[0]);     
}

2
IE10+支持FileReader -- http://caniuse.com/filereader -- 但是显然有一个polyfill存在,https://github.com/Jahdrien/FileReader - Cory Mawhorter
1
你如何在没有按钮的情况下运行代码?示例中的“e”是什么意思? - Waltari
1
@Waltari,“e”变量是使用FileReader API的文件句柄事件,如果不使用文件输入或拖放区域,您将无法完成此操作,因为据我所知,您不能通过编程方式运行用户的文件系统。 - DerekR
在 jsfiddle 链接的示例中,当我从我的电脑选择一张照片后,画布没有更新。我使用的是 Windows 10 和 Chrome 70.0.3538.77。 - TheLogicGuy
@TheLogicGuy现在应该已经修复了。显然,那个小工具使用了MooTools库,而该库已经停止工作了。 - DerekR

31

不需要使用FileReader*,最好使用URL.createObjectURL方法,它将直接创建一个符号链接到磁盘上的文件。这将减少内存使用,并且有额外的好处,只需等待一个异步事件(即img.onload)。

document.getElementById('inp').onchange = function(e) {
  var img = new Image();
  img.onload = draw;
  img.onerror = failed;
  img.src = URL.createObjectURL(this.files[0]);
};
function draw() {
  var canvas = document.getElementById('canvas');
  canvas.width = this.width;
  canvas.height = this.height;
  var ctx = canvas.getContext('2d');
  ctx.drawImage(this, 0,0);
}
function failed() {
  console.error("The provided file couldn't be loaded as an Image media");
}
<input type="file" id="inp">
<canvas id="canvas"></canvas>

*据我所知,只有Chrome的几个版本支持FileReader,但还不支持URL.createObejctURL,所以如果你的目标是这些特定版本,你可能需要使用FileReader。


如何调整图像大小以适应画布? - Abhinav Ravi
2
@AbhinavRavi 通常是反过来的:调整画布大小以适应图像。但如果您真的想更改图像的大小,那么只需使用drawImage的第三个和第四个参数:ctx.drawImage(img, x, y, width, height) - Kaiido
2
这个解决方案在Chrome 71版本以后存在问题。 - Matt Kenefick
2
@MattKenefick 有什么问题? - Crashalot
@Kaiido,自从新版本的Chrome存在这个问题以来,是否有更新的答案? - Crashalot
显示剩余3条评论

0

通过修改 @kaiido 的答案,每次创建一个新的 canvas 元素并将其附加到包装器中。在不知道可能需要多少个画布时非常有用。

注意:不存在 new Canvas() 构造函数,因此我们必须使用 createElement()

document.getElementById('inp').onchange = function(e) {
  let img = new Image();
  img.onload = draw;
  img.onerror = failed;
  img.src = URL.createObjectURL(this.files[0]);
};

function draw() {
  let canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d');
  canvas.width = this.width;
  canvas.height = this.height;
  ctx.drawImage(this, 0, 0);
  document.getElementById('gallery').append(canvas);
}

function failed() {
  console.error("The provided file couldn't be loaded as an Image media");
}
/* entirely decorative */

#gallery {
  display: flex;
  gap: 1em;
  margin: 1em;
}

#gallery canvas {
  height: 100px;
  border-radius: .5em;
  aspect-ratio: 1/1;
  object-fit: cover;
}
<input type="file" id="inp">
<div id='gallery'></div>


-1

创建一个画布可消耗的图像的最佳方法是使用从输入获取的文件创建ImageBitmap

这将使用优化路径来生成浏览器渲染图像所需的内容,并将位图数据存储在GPU中,以便在需要时快速绘制。

考虑到这是一个相当新的功能(Safari仅在去年添加了支持),您可能希望使用类似我的这个的polyfill。

document.querySelector("input").oninput = async (evt) => {
  try {
    const file = evt.target.files[0];
    const bitmap = await createImageBitmap(file);
    const canvas = document.querySelector("canvas");
    canvas.width = bitmap.width;
    canvas.height = bitmap.height;
    const ctx = canvas.getContext("2d");
    ctx.drawImage(bitmap, 0, 0);
  }
  catch(err) {
    console.error(err);
  }
};
<!-- createImageBitmap polyfill for old browsers --> <script src="https://cdn.jsdelivr.net/gh/Kaiido/createImageBitmap/dist/createImageBitmap.js"></script>
<input type="file">
<canvas></canvas>


-5
<script>
window.onload = function() {
var canvas=document.getElementById(“drawing”); // grabs the canvas element
var context=canvas.getContext(“2d”); // returns the 2d context object
var img=new Image() //creates a variable for a new image

img.src= “images/vft.jpg// specifies the location of the image
context.drawImage(img,20,20); // draws the image at the specified x and y location
}
</script>

请检查演示


1
这个问题的踩数让我很好奇。问题出在这一行代码:img.src=“images/vft.jpg”。问题是如何动态解决它,基于用户上传的内容(任何文件名!),而不仅仅是静态地解决该文件。 - HoldOffHunger
2
@HoldOffHunger并不会等待图像加载完成后再尝试在画布上绘制它,这对于用户提供的图像来说几乎每次都会失败,因为该图像通常不会被缓存。 - Kaiido
1
富文本引用也不好玩。 - ggorlen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接