前端开发系列029-基础篇之Canvas绘图(压缩)
写这篇文章的原因是因为今天早上的时候,突然遇到个需求需要等比例调整照片的大小(主要是想把图片等比例的缩小),我在Mac上通过图片处理软件捣鼓的时候发现比较麻烦,就随手百度了一个在线修改图片尺寸的网站,叫做[改图宝](http://www.gaitubao.com/)。这个网站提供给图片加logo、修改图片尺寸以及印章制作等诸多功能,界面简洁使用方便解决了我的问题,值得推荐。
然而,等到中午的时候,我发现还有一张图片需要处理,恰好电脑连不上网络,我就考虑能不能通过代码自己来实现,因为图片的选择 - 压缩 - 上传在实际开发中也是对应的场景,因此本文将介绍如何利用Canvas画布来对图片进行压缩的技术,包括实现思路和具体的代码。

[ 1 ] 获取源图像数据
在页面中我们使用input标签(file类型)来让用户选择对应的文件上传。为了等比例的对图片进行压缩,需要获取源图片的宽度和高度等数据参数,这里使用了FileReader构造函数(类)。
具体实现的时候,先调用new FileReader()创建一个FileReader的实例对象,然后为input标签注册change事件监听。当用户选择好文件后,需要先检查是否是图片(通过MIMEType类型判断),再通过FileReader实例来调用readAsDataURL(file)方法来读取图片文件的数据信息,以获取源图片文件的宽度和高度信息。
[ 2 ] 计算宽高压缩比数据
因为示例代码中演示的等比例的进行缩放(压缩),因此需要通过得到目标图片的宽度和高度尺寸数据。
这里列出计算部分的核心代码
var targetWidth,targetHeight;
var imgWidth = img.width, imgHeight = img.height;
var maxWidth = 150, maxHeight = 150;
// 如果图片尺寸超过限制,那么需要重新计算宽高
if (imgWidth > maxWidth || imgHeight > maxHeight) {
if (imgWidth / imgHeight >= 1) {
// 如果更宽,那么就按照宽度限定尺寸
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (imgHeight / imgWidth));
} else {
// 如果更高,那么就按照高度限定尺寸
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (imgWidth / imgHeight));
}
}
[ 3 ] 绘制目标图片
当目标图片(压缩后)的宽高都计算完成后,可以通过Canvas上下文的drawImage方法来完成图片的绘制,该方法的具体使用可以参考[ javaScript系列 [14]-Canvas绘图(图像)](http://wendingding.com/2019/02/05/javaScript系列 [14]-Canvas绘图(图像)这篇文章。
drawImage方法的第一个参数为需要绘制的图片数据,该图片数据即为用户通过input标签选择的文件内容。当然,在具体实现的时候还需要读取文件的内容,监听加载完毕之后再设置Image数据源。
reader.onload = function(event) {
/e.target.result是图片的base64地址信息
img.src = event.target.result;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="file" id="file">
<div id="info" style="font-size: 13px"></div>
<canvas id="canvas" height="200" width="200"></canvas>
<script>
//[1] 获取页面中的文件选择标签
var oInput = document.querySelector('#file');
//[2] 创建FileReader对象用于读取文件信息
var reader = new FileReader();
var file = null; //文件对象
//[3] 给文件选择标签添加事件监听
oInput.addEventListener('change', function (event) {
//001 获取用户选择的文件
file = event.target.files[0];
//002 获取文件的MIMEType类型
var fileType = file.type;
//003 检查用户选择的文件是否是图片
if (fileType.indexOf("image") == 0) {
//004 如果发现文件是图片则读取图片为DataURL
reader.readAsDataURL(file);
}
});
//[4] 创建Image图像实例
var img = new Image();
var targetWidth,targetHeight;
//[5] 监听FileReader对象是否处理完毕,设置图像实例的数据源
reader.onload = function(event) {
//说明:e.target.result是图片的base64地址信息
img.src = event.target.result;
}
//[6] 监听Image实例加载,压缩图片并生成预览图像
img.onload = function () {
setFileInfo();
//[7]在页面中创建canvas画布对图片进行缩放(压缩)后绘制
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
}
function setFileInfo() {
// 获取文件的名称
var fileName = file.name;
// 获取文件的大小
var fileSize = (file.size / 1024 / 1024).toFixed(3) + "M";
// 图片压缩比计算
var imgWidth = img.width, imgHeight = img.height;
var maxWidth = 150, maxHeight = 150;
// 如果图片尺寸超过限制,那么需要重新计算宽高
if (imgWidth > maxWidth || imgHeight > maxHeight) {
if (imgWidth / imgHeight >= 1) {
// 如果更宽,那么就按照宽度限定尺寸
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (imgHeight / imgWidth));
} else {
// 如果更高,那么就按照高度限定尺寸
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (imgWidth / imgHeight));
}
//在页面中显示图片信息
var html = "<div>1.已选择图片" + fileName + ",大小为" + fileSize + "。</div>\n" +
"<div>2.图片原尺寸是:" + imgWidth + " x " + imgHeight + "</div>\n" +
"<div>3.图片压缩尺寸:" + maxWidth + " x " + maxHeight + "</div>\n" +
"<div>4.图片已压缩为:" + targetWidth + " x " + targetHeight +"</div>\n";
var oDiv = document.getElementById("info");
oDiv.innerHTML = html;
}
};
</script>
</body>
</html>

前端开发系列029-基础篇之Canvas绘图(压缩)的更多相关文章
- 从0到1用react+antd+redux搭建一个开箱即用的企业级管理后台系列(基础篇)
背景 最近因为要做一个新的管理后台项目,新公司大部分是用vue写的,技术栈这块也是想切到react上面来,所以,这次从0到1重新搭建一个react项目架子,需要考虑的东西的很多,包括目录结构.代码 ...
- 前端开发:css基础知识之盒模型以及浮动布局。
前端开发:css基础知识之盒模型以及浮动布局 前言 楼主的蛮多朋友最近都在学习html5,他们都会问到同一个问题 浮动是什么东西? 为什么这个浮动没有效果? 这个问题楼主已经回答了n遍.今天则是把 ...
- ESP8266开发之旅 基础篇① 走进ESP8266的世界
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- openlayers5-webpack 入门开发系列一初探篇(附源码下载)
前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...
- leaflet-webpack 入门开发系列一初探篇(附源码下载)
前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...
- 【Windows10 IoT开发系列】配置篇
原文:[Windows10 IoT开发系列]配置篇 Windows10 For IoT是Windows 10家族的一个新星,其针对不同平台拥有不同的版本.而其最重要的一个版本是运行在Raspberry ...
- ESP8266开发之旅 基础篇④ ESP8266与EEPROM
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
随机推荐
- 能详细地讲讲stm32该怎么学吗?
作为一个在嵌入式领域摸爬滚打了好几年的老兵,我想分享一下我学习STM32的心路历程和方法论.坦白说,刚开始接触STM32时,我也是一脸懵逼.机械专业毕业的我转行做嵌入式,第一份工作被调剂到电子部门,实 ...
- 详细介绍FutureTask类
一.详细介绍FutureTask类 FutureTask 未来将要执行的任务对象,继承 Runnable.Future 接口,用于包装 Callable 对象,实现任务的提交 public stati ...
- Java 21 新特性
Java 21 是 Java 语言的一次重要更新,引入了若干新的特性,提升了开发者的编程效率和代码质量.本文将详细介绍 Java 21 的新特性,包括基础概念.使用方法.常见实践以及最佳实践. 简介 ...
- MySQL 的 Doublewrite Buffer 是什么?它有什么作用?
MySQL 的 Doublewrite Buffer 是什么?它有什么作用? Doublewrite Buffer 是 InnoDB 存储引擎的一种机制,旨在提高数据的安全性,防止在写入磁盘时发生崩溃 ...
- 什么是 Java 中的 JIT(Just-In-Time)?
Java 中的 JIT(Just-In-Time)编译器 1. JIT 的定义 JIT(Just-In-Time)编译器是一种用于 Java 虚拟机(JVM)的动态编译技术.它在 Java 程序运行时 ...
- 有的时候,需要利用UserControl占位模板,动态替换的情况,绑定后无法获取DataContext的问题
有的时候,需要利用UserControl占位模板,动态替换的情况,绑定后无法获取DataContext的问题,特此备注下 效果如下: 关键的地方是,下面第3行,需要把当前的上下文传递到Content, ...
- 【BUG】.NET项目|未能加载文件或程序集“xxx”,或它的某一个依赖项。系统找不到指定的文件的通解
出错代码: MSBuildWorkspace workspace = CreateWorkspace(); Solution solution = workspace.OpenSolutionAsyn ...
- MethodImpl优化性能
参数解释 MethodImplOptions.AggressiveInlining:请求编译器在可能的情况下对方法进行内联. MethodImpl:这是一个属性,允许开发者为方法指定特定的实现行为,比 ...
- C# 利用反射模拟多态效果
public class A { } public class B : A { } public class C : A { } public static class Extension { pub ...
- 基于 SSE、asp.net core razor 实现比分Live
前言 最近在项目中用到了 SSE (Server-Sent Events),用于服务的单向长连接数据推送.因为都是使用 C# 实现的,所以服务端使用的是 HttpListener ,而客户端更简单,只 ...