写这篇文章的原因是因为今天早上的时候,突然遇到个需求需要等比例调整照片的大小(主要是想把图片等比例的缩小),我在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绘图(压缩)的更多相关文章

  1. 从0到1用react+antd+redux搭建一个开箱即用的企业级管理后台系列(基础篇)

    背景 ​ 最近因为要做一个新的管理后台项目,新公司大部分是用vue写的,技术栈这块也是想切到react上面来,所以,这次从0到1重新搭建一个react项目架子,需要考虑的东西的很多,包括目录结构.代码 ...

  2. 前端开发:css基础知识之盒模型以及浮动布局。

    前端开发:css基础知识之盒模型以及浮动布局 前言 楼主的蛮多朋友最近都在学习html5,他们都会问到同一个问题 浮动是什么东西?  为什么这个浮动没有效果?  这个问题楼主已经回答了n遍.今天则是把 ...

  3. ESP8266开发之旅 基础篇① 走进ESP8266的世界

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  4. ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  5. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  6. openlayers5-webpack 入门开发系列一初探篇(附源码下载)

    前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...

  7. leaflet-webpack 入门开发系列一初探篇(附源码下载)

    前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...

  8. 【Windows10 IoT开发系列】配置篇

    原文:[Windows10 IoT开发系列]配置篇 Windows10 For IoT是Windows 10家族的一个新星,其针对不同平台拥有不同的版本.而其最重要的一个版本是运行在Raspberry ...

  9. ESP8266开发之旅 基础篇④ ESP8266与EEPROM

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  10. ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

随机推荐

  1. MySQL隐藏手机号

    1.实现方法 通过MySQL的left.right.contact函数实现 2.语法说明 contact()函数 作用:将多个字符串连接成一个字符串 语法:concat(字符串1,....,字符串n) ...

  2. Semaphore.acquire()方法的底层原理

    一.acquire() 的工作流程 当调用 acquire() 方法时,实际调用的是 AQS 的 acquireSharedInterruptibly(1) 方法.以下是其详细工作流程: // acq ...

  3. Spring 整合 Junit

    一.导入jar包 二.使用@RunWith 注解替换原有运行器 [main()] /** * * @Company http://www.ithiema.com * @Version 1.0 */ @ ...

  4. 16.1k star! 只需要DDL就能一键生成数据库关系图!开源神器ChartDB让你的数据结构"看得见"

    嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 ChartDB是一款开源的数据库可视化神器,通过一句智能查询就能自动生成专业的数据库关系图. ...

  5. 【记录】Truenas Scale|中危漏洞,需要SMB签名

    部分内容参考:等保测试问题--需要SMB签名(SMB Signing not Required) 以及 ChatGPT. Truenas常用SMB服务,但默认并不开启SMB签名.这样具有中间人攻击的风 ...

  6. Pandas 实现 Excel 多列 转 多行

    也是最近的一个需求, 将一个 Excel 表, 多列转多行, 就把那种行的, 业务人员经常搞的那种垃圾表,给它转为咱熟悉的数据库表的形式, 多列转多行. 还要帮他们处理数据, 恶心得一批, 其实也不一 ...

  7. AI 技术发展简史

    AI 智能体开发指南 AI技术发展简史 一.AI的定义与核心目标 人工智能(Artificial Intelligence,AI)自诞生以来,一直是计算机科学和软件工程领域的重要研究方向.随着计算能力 ...

  8. Markdown 使用十分钟入门

    Markdown 十分钟入门 标题 标题前#+空格 支持6级标题 输入样式#+空格:##+空格:以此类推, *注意标题输入的#前面不能有空格 字体 斜体 # 这里不要空格 _斜体_ *加一个* 字体加 ...

  9. LLM主要架构

    LLM本身基于Transformer架构 自2017年,Attention is all you need诞生起,原始的Transformer模型不同领域的模型提供了灵感和启发 基于原始的Transf ...

  10. Jenkins自动化部署-----持续交付

    前言: 感谢之前带领过我的leader,让我能够知道什么是好的开发方法. 在很早之前就接触过敏捷开发.什么是敏捷开发,简单来说就是让软件可靠地,快速地发布出来的一种开发方法和技巧. 而敏捷开发中有许多 ...