It's a massive honor to have Tom "Trenkavision" Trenka write a guest post for this blog. Tom was one of the original contributors of the Dojo Toolkit and my mentor at SitePen. I've seen his genius first hand and he's always the first one to foresee issues with a potential solution. He also thinks outside the box, coming up with unconventional but reliable solutions to edge case problems. This is a perfect example.
让Tom“ Trenkavision” Trenka为这个博客写客座帖子,这是非常荣幸。 Tom是Dojo Toolkit的原始作者之一,也是我在SitePen的导师。 我亲眼目睹了他的天才,他始终是第一个预见到具有潜在解决方案问题的人。 他还开创了思路,提出了解决边缘案例问题的非常规但可靠的解决方案。 这是一个完美的例子。
Recently I was asked to create a user interface that allows someone to upload an image to a server (among other things) so that it could be used in the various web sites my company provides to its clients. Normally this would be an easy task—create a form with a File input, let someone navigate to the image in question on their computer, and upload it using multipart/form-data as the enctype in the form tag. Simple enough, right? In fact, there's a simple enough example right on this site.
最近,有人要求我创建一个用户界面,该界面允许某人将图像上传到服务器(除其他外),以便可以在公司向其客户提供的各种网站中使用该图像。 通常,这是一项容易的任务-使用文件输入创建表单,让某人导航到计算机上有问题的图像,然后使用multipart/form-data作为form标签中的enctype上载该图像。 很简单,对不对? 实际上, 此站点上有一个足够简单的示例。
But what if you had pre-prepare that image in some way? In other words, what if you had to resize that image first? What if you needed that image to be a particular file type, like a PNG or a JPG? Canvas to the rescue!
但是,如果您已经以某种方式预先准备了该图像怎么办? 换句话说,如果必须先调整该图像的大小怎么办? 如果您需要将该图像设为特定的文件类型(如PNG或JPG),该怎么办? 帆布救援!
View Demo 观看演示The Canvas is a DOM element, added in HTML5, that allows a user to draw graphics directly in a page, usually through JavaScript. It is different from specifications such as SVG or VML in that it is a raster API as opposed to a vector API; think of it as the difference between drawing something using Adobe Illustrator (vector graphics) and working with something using Adobe Photoshop (raster).
Canvas是HTML5中添加的DOM元素,它使用户通常可以通过JavaScript在页面中直接绘制图形。 它与SVG或VML等规范不同,因为它是栅格 API,而不是矢量 API。 可以认为这是使用Adobe Illustrator(矢量图形)绘制某些内容和使用Adobe Photoshop(光栅)处理某些内容之间的区别。
Among the things a canvas can do is read and render images, and allow you to manipulate that image data using JavaScript. There are many articles out there that show you some of the basics of image manipulation—the majority them focusing on various image filtering techniques—but we just need to be able to resize our image to a certain specification, and a canvas can do that no problem.
画布可以做的事情之一就是读取和渲染图像,并允许您使用JavaScript处理该图像数据。 那里有很多文章向您展示了图像处理的一些基础知识-大多数文章着眼于各种图像过滤技术-但是我们只需要能够将图像调整为特定规格,画布就可以做到这一点。问题。
Say our requirements are to ensure that an image is no taller than, say, 100 pixels no matter what the original height was. Here's the basic code to do this:
说我们的要求是确保无论原始高度如何,图像都不会高于例如100像素。 这是执行此操作的基本代码:
var MAX_HEIGHT = 100; function render(src){ var image = new Image(); image.onload = function(){ var canvas = document.getElementById("myCanvas"); if(image.height > MAX_HEIGHT) { image.width *= MAX_HEIGHT / image.height; image.height = MAX_HEIGHT; } var ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); canvas.width = image.width; canvas.height = image.height; ctx.drawImage(image, 0, 0, image.width, image.height); }; image.src = src; }Here's what that example does:
该示例将执行以下操作:
Create a JavaScript Image object. 创建一个JavaScript Image对象。Attach a handler to the onload event of that Image.
将处理程序附加到该Image的onload事件。
Check to see what the dimensions of the loaded image is, and if the original image's height is greater than our maximum allowed, change those dimensions. 检查加载的图像的尺寸是什么,如果原始图像的高度大于我们允许的最大值,请更改这些尺寸。 Clear anything that is in our canvas element. 清除画布元素中的所有内容。 Set the canvas dimensions to the dimensions of the Image, and 将画布尺寸设置为图像的尺寸,然后 Draw the image to the canvas. 将图像绘制到画布上。From there, you can use the toDataURL method of the Canvas API to get a Base 64-encoded version of the image to do with what you will.
从那里,您可以使用Canvas API的toDataURL方法来获取图像的Base 64编码版本,以完成您的工作。
Well Padawan, I'm glad you asked. You can't use the File Input for that; the only information you can get from that element is the path to the file someone chose. You could use that path information to try to load that image, but that technique is unreliable across browsers. So instead, we'll use the HTML5 File API to read a file off someone's disk, and use that as the source.
好吧,Padawan,很高兴您问到。 您不能为此使用文件输入; 您可以从该元素获得的唯一信息是某人选择的文件的路径。 您可以使用该路径信息来尝试加载该图像,但是该技术在浏览器之间并不可靠。 因此,相反,我们将使用HTML5 File API从某人的磁盘读取文件,并将其用作源。
The new File API is a way of reading and listing files on a user's local disk without violating any kind of security sandbox—so that a malicious website can't, say, write a virus to a user's disk. The object we're going is use is the FileReader, which will allow a developer to read (in various ways) the contents of a file.
新的File API是一种在不违反任何类型的安全沙箱的情况下读取和列出用户本地磁盘上的文件的方法,从而使恶意网站无法将病毒写入用户磁盘。 我们要使用的对象是FileReader ,它允许开发人员阅读(以各种方式)文件的内容。
Assuming we know the path to the image in question, using FileReader to load the contents and render it using the code above is pretty easy to do:
假设我们知道问题图像的路径,使用FileReader加载内容并使用上面的代码呈现它很容易做到:
function loadImage(src){ // Prevent any non-image file type from being read. if(!src.type.match(/image.*/)){ console.log("The dropped file is not an image: ", src.type); return; } // Create our FileReader and run the results through the render function. var reader = new FileReader(); reader.onload = function(e){ render(e.target.result); }; reader.readAsDataURL(src); }What we are doing here is creating a FileReader object, adding a handler to the onload method to do something with the results, and then reading the file contents. Pretty simple, right?
我们在这里所做的是创建一个FileReader对象,向onload方法添加一个处理程序以对结果进行处理,然后读取文件内容。 很简单,对吧?
Silly rabbit, be patient! Of course that is our next step. There's a number of ways to do that; for instance, you could have a simple text input to make someone enter a path to an object, but obviously most people are not developers, and would not have a real clue as to how to do that properly. To make it easy on our users, we'll use the Drag and Drop API...
傻兔子,请耐心等待! 当然,这是我们的下一步。 有很多方法可以做到这一点。 例如,您可以使用简单的文本输入来使某人输入到对象的路径,但是显然大多数人都不是开发人员,并且对于如何正确执行此操作没有真正的线索。 为了方便用户使用,我们将使用拖放 API ...
The Drag and Drop API is very simple—it consists of a set of DOM events carried by most DOM elements, to which you attach handler functions. We want to let a user take a file from somewhere on their disk, drag it onto an element, and do something with it. Here's our setup:
拖放API非常简单-它由大多数DOM元素承载的一组DOM事件组成,您将处理程序函数附加到该事件。 我们想让用户从磁盘上的某个位置取一个文件,将其拖到一个元素上,然后对其进行处理。 这是我们的设置:
var target = document.getElementById("drop-target"); target.addEventListener("dragover", function(e){e.preventDefault();}, true); target.addEventListener("drop", function(e){ e.preventDefault(); loadImage(e.dataTransfer.files[0]); }, true);This is pretty simple:
这很简单:
We designate an element as our drop target,
我们指定一个元素作为放置目标 ,
We prevent anything from happening when something is dragged over it... 当有东西拖到上面时,我们可以防止任何事情发生。...and when someone drops something on our target, we prevent any default action and send the first file in the event's dataTransfer object to our loadImage function.
......当有人丢弃针对我们的东西,我们要阻止任何默认动作和事件的第一个文件发送dataTransfer对象给我们loadImage功能。
Now there are other things we can do, such as add some kind of preview of the Image. But most of this seems useless without being able to save the resized image. For that, we'll use Ajax to do an HTTP POST of the image data. The next example uses the Dojo Toolkit's Request module, but you can use any typical Ajax technique you'd like (we're assuming DTK 1.9.x for this example):
现在,我们还可以做其他事情,例如添加Image的某种预览。 但是,如果没有保存调整大小后的图像,其中的大多数功能似乎就毫无用处。 为此,我们将使用Ajax对图像数据进行HTTP POST。 下一个示例使用Dojo Toolkit的Request模块,但是您可以使用所需的任何典型Ajax技术(此示例假定DTK 1.9.x):
// Remember that DTK 1.7+ is AMD! require(["dojo/request"], function(request){ request.post("image-handler.php", { data: { imageName: "myImage.png", imageData: encodeURIComponent(document.getElementById("canvas").toDataURL("image/png")) } }).then(function(text){ console.log("The server returned: ", text); }); });We use the toDataURL of the Canvas API to get our Base64-encoded version of our image; note the encodeURIComponent method wrapping it. Some Ajax APIs will do this for you, but it is better to be safe than sorry.
我们使用Canvas API的toDataURL来获取图像的Base64编码版本; 注意包装它的encodeURIComponent方法。 某些Ajax API会为您完成此操作,但是安全起着总比后悔好。
View Demo 观看演示That's it! That's all you need to create an intuitive user interface that allows you to control the size of an image and post it to a server without needing complex multi-part handlers on your server!
而已! 这就是创建直观的用户界面所需的全部操作,该界面使您可以控制图像的大小并将其发布到服务器,而无需服务器上复杂的多部分处理程序!
翻译自: https://davidwalsh.name/resize-image-canvas