首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >前端图片压缩

前端图片压缩

作者头像
码客说
发布于 2022-12-01 09:32:58
发布于 2022-12-01 09:32:58
3K00
代码可运行
举报
文章被收录于专栏:码客码客
运行总次数:0
代码可运行

图片压缩流程

压缩图片基本流程

  • input 读取到 文件 ,使用 FileReader 将其转换为 base64 编码
  • 新建 img ,使其 src 指向刚刚的 base64
  • 新建 canvas ,将 img 画到 canvas 上
  • 利用 canvas.toDataURL/toBlob 将 canvas 导出为 base64 或 Blob
  • 将 base64 或 Blob 转化为 File 将这些步骤逐个拆解,我们会发现似乎在canvas.toDataURL时涉及到图片质量,那咱们就从这里下手。

准备

HTMLCanvasElement.toDataURL()

HTMLCanvasElement.toDataURL() 方法返回一个包含图片展示的 data URI 。

可以使用 type 参数其类型,默认为 PNG 格式。

图片的分辨率为96dpi。

  • 如果画布的高度或宽度是0,那么会返回字符串data:,
  • 如果传入的类型非image/png,但是返回的值以data:image/png开头,那么该传入的类型是不支持的。

语法

canvas.toDataURL(type, encoderOptions);

参数

  • type 可选 图片格式,默认为 image/png
  • encoderOptions 可选 在指定图片格式为 image/jpegimage/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。 如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。 Chrome支持image/webp类型。

JS

压缩比例在0.9以下都会明显的文件变小,建议0.8

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>图片压缩</title>
</head>
<body>
<input type="file" name="pic" id="pic">
<br/><br/>
<img src="" alt="" class="imgleft"/>
<img src="" alt="" class="imgright"/>

<script>
  /**
   * 压缩图片方法
   * @param {file} file 文件
   * @param {Number} quality 图片质量(取值0-1之间默认0.92)
   */
  function compressImg(file, quality) {
    var qualitys = 0.52
    if (parseInt((file.size / 1024).toFixed(2)) < 1024) {
      qualitys = 0.85
    }
    if (5 * 1024 < parseInt((file.size / 1024).toFixed(2))) {
      qualitys = 0.92
    }
    if (quality) {
      qualitys = quality
    }
    if (file[0]) {
      return Promise.all(Array.from(file).map(e => compressImg(e,
          qualitys))) // 如果是 file 数组返回 Promise 数组
    } else {
      return new Promise((resolve) => {
        if ((file.size / 1024).toFixed(2) < 300) {
          resolve({
            file: file
          })
        } else {
          const fileReader = new FileReader() // 创建 FileReader
          fileReader.onload = ({target: {result: src}}) => {
            const image = new Image() // 创建 img 元素
            image.onload = async () => {
              const mCanvas = document.createElement('canvas') // 创建 canvas 元素
              const mCtx = mCanvas.getContext('2d')
              var targetWidth = image.width
              var targetHeight = image.height
              var originWidth = image.width
              var originHeight = image.height
              if (1024 <= parseInt((file.size / 1024).toFixed(2)) && parseInt((file.size / 1024).toFixed(2)) <= 10 * 1024) {
                var maxWidth = 1600
                var maxHeight = 1600
                targetWidth = originWidth
                targetHeight = originHeight
                // 图片尺寸超过的限制
                if (originWidth > maxWidth || originHeight > maxHeight) {
                  if (originWidth / originHeight > maxWidth / maxHeight) {
                    // 更宽,按照宽度限定尺寸
                    targetWidth = maxWidth
                    targetHeight = Math.round(maxWidth * (originHeight / originWidth))
                  } else {
                    targetHeight = maxHeight
                    targetWidth = Math.round(maxHeight * (originWidth / originHeight))
                  }
                }
              }
              if (10 * 1024 <= parseInt((file.size / 1024).toFixed(2)) && parseInt((file.size / 1024).toFixed(2)) <= 20 * 1024) {
                maxWidth = 1400
                maxHeight = 1400
                targetWidth = originWidth
                targetHeight = originHeight
                // 图片尺寸超过的限制
                if (originWidth > maxWidth || originHeight > maxHeight) {
                  if (originWidth / originHeight > maxWidth / maxHeight) {
                    // 更宽,按照宽度限定尺寸
                    targetWidth = maxWidth
                    targetHeight = Math.round(maxWidth * (originHeight / originWidth))
                  } else {
                    targetHeight = maxHeight
                    targetWidth = Math.round(maxHeight * (originWidth / originHeight))
                  }
                }
              }
              mCanvas.width = targetWidth
              mCanvas.height = targetHeight
              mCtx.clearRect(0, 0, targetWidth, targetHeight)
              mCtx.drawImage(image, 0, 0, targetWidth, targetHeight) // 绘制 canvas
              const canvasURL = mCanvas.toDataURL('image/jpeg', qualitys)
              const buffer = atob(canvasURL.split(',')[1])
              let length = buffer.length
              const bufferArray = new Uint8Array(new ArrayBuffer(length))
              while (length--) {
                bufferArray[length] = buffer.charCodeAt(length)
              }
              const miniFile = new File([bufferArray], file.name, {
                type: 'image/jpeg'
              })
              resolve({
                beforeFile: file,
                afterFile: miniFile,
                beforeSrc: src,
                afterSrc: canvasURL,
                beforeKB: Number((file.size / 1024).toFixed(2)),
                afterKB: Number((miniFile.size / 1024).toFixed(2))
              })
            }
            image.src = src
          }
          fileReader.readAsDataURL(file)
        }
      })
    }
  }

  // 获得元素对象
  var fileDom = document.querySelector('#pic');
  var imgleft = document.querySelector('.imgleft');
  var imgright = document.querySelector('.imgright');

  // 当上传框发生变化的时候,显示对应的图片
  fileDom.onchange = async function () {
    imgleft.src = window.URL.createObjectURL(fileDom.files[0]);
    let result = await compressImg(fileDom.files[0],0.8)
    console.info(result);
    imgright.src = result.afterSrc;
  }
</script>

<style>
  .imgleft {
    width: 500px;
  }

  .imgright{
    width: 500px;
  }

</style>
</body>
</html>

TS版本

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const fileToDataURL = (file: Blob): Promise<any> => {
  return new Promise((resolve) => {
    const reader = new FileReader()
    reader.onloadend = (e) => resolve((e.target as FileReader).result)
    reader.readAsDataURL(file)
  })
}
const dataURLToImage = (dataURL: string): Promise<HTMLImageElement> => {
  return new Promise((resolve) => {
    const img = new Image()
    img.onload = () => resolve(img)
    img.src = dataURL
  })
}
const canvastoFile = (canvas: HTMLCanvasElement, type: string, quality: number): Promise<Blob | null> => {
  return new Promise((resolve) => canvas.toBlob((blob) => resolve(blob), type, quality))
}
/**
 * 图片压缩方法
 * @param {Object}  file 图片文件
 * @param {String} type 想压缩成的文件类型
 * @param {Nubmber} quality 压缩质量参数
 * @returns 压缩后的新图片
 */
export const compressionFile = async(file, type = 'image/jpeg', quality = 0.5) => {
  const fileName = file.name
  const canvas = document.createElement('canvas')
  const context = canvas.getContext('2d') as CanvasRenderingContext2D
  const base64 = await fileToDataURL(file)
  const img = await dataURLToImage(base64)
  canvas.width = img.width
  canvas.height = img.height
  context.clearRect(0, 0, img.width, img.height)
  context.drawImage(img, 0, 0, img.width, img.height)
  const blob = (await canvastoFile(canvas, type, quality)) as Blob // quality:0.5可根据实际情况计算
  const newFile = await new File([blob], fileName, {
    type: type
  })
  return newFile
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-11-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
开箱即用的前端图片压缩方案
我们都知道在“寸土寸金”的互联网时代, 速度是第一竞争力, 虽然我们的5G发展已经摇摇领先, 但是也经不住用户在一个网页里传很多“巨无霸”图片, 最终导致的结果就是页面“龟速”打开......
徐小夕
2022/09/27
1.4K0
开箱即用的前端图片压缩方案
前端图片压缩方案及代码实现
随着互联网的发展,图片在各种网站和应用中铺天盖地,运营人员在后台管理系统中上传图片时常常忽略的图片的体积大小,随之产生的带宽和服务器容量也大大增加,图片压缩的需求随之产生。
越陌度阡
2023/02/13
1.5K0
前端图片压缩方案及代码实现
使用canvas在前端压缩图片实例页面
HTML代码: <input id="file" type="file"> JS代码: var eleFile = document.querySelector('#file'); // 压缩图片需要的一些元素和对象 var reader = new FileReader(), img = new Image(); // 选择的文件对象 var file = null; // 缩放图片需要的canvas var canvas = document.createElement('canvas'); va
李维亮
2021/07/08
4620
移动拍照上传图片实现图片压缩
手机拍照一般手机需要5m大小的内存上传过程需要流量大,上传时间长的问题,为更好的用户体验需要对图片进行压缩。
用户6379025
2022/12/26
1.9K0
【Web技术】907- 前端图片最优化压缩方案
上传图片/视频/文件是我们经常会遇到的问题,但是一旦图片过大就会导致不好的操作体验。图片上传是前端中常见的的业务场景。无论是前台还是后台,适当的对图片进行压缩处理, 可以显著的提升用户体验。而在后台管理系统中,图片压缩不仅仅能够提升后台管理员操作体验,更是可以防止后台设置过大的图片导致前台图片加载过久,从而影响用户体验。
pingan8787
2021/04/07
1K0
【Web技术】907- 前端图片最优化压缩方案
Vue 图片压缩并上传至服务器
本文主要讲解基于 Vue + Vant ,实现移动端图片选择,并用 Canvas 压缩图片,最后上传至服务器。还会封装一个工具类,方便直接调用。
solocoder
2022/04/06
2.5K0
Vue 图片压缩并上传至服务器
Canvas 进阶(六)实现图片压缩功能
因此我们设计一个 imageCompress 类,传入一个 option, 其参数有:
小皮咖
2020/02/25
1.5K0
Canvas 进阶(六)实现图片压缩功能
详解 JS 压缩图片
作者 | wuwhs https://segmentfault.com/a/1190000023486410
五月君
2020/09/17
13.9K0
ant design中upload组件 上传图片压缩
不想描述多余的,直接看代码简单直接 const [defaultFileList, setDefaultFileList] = useState([]); <Upload accept="image/*" customRequest={uploadImage} onChange={handleOnChange} listType="picture-card"
我乃小神神
2021/12/07
1.6K0
《你不知道的 Blob》番外篇
原文对 Blob 的知识点介绍得非常完整清晰,本文通过四个问题来总结本文核心知识:
pingan8787
2020/06/08
2.8K0
JS 图片压缩
说起图片压缩,大家想到的或者平时用到的很多工具都可以实现,例如,客户端类的有图片压缩工具 PPDuck3, JS 实现类的有插件 compression.js ,亦或是在线处理类的 OSS 上传,文件上传后,在访问文件时中也有图片的压缩配置选项,不过,能不能自己撸一套 JS 实现的图片压缩代码呢?当然可以,那我们先来理一下思路。
政采云前端团队
2020/04/27
28.8K0
这个图片压缩神器,直接可以在前端用
想必大家都用过图片压缩工具吧!对于前端来说这图片压缩是必不可少的,今天就给大家介绍一个js工具库,让前端也能实现图片压缩~
程序员老鱼
2024/07/12
6230
这个图片压缩神器,直接可以在前端用
前端实现图片压缩干货分享
在Web开发中,图片压缩是一个常见且重要的需求。随着高清图片和多媒体内容的普及,如何在保证图片质量的同时减少其文件大小,对于提升网页加载速度、优化用户体验至关重要。前端作为用户与服务器之间的桥梁,实现图片压缩的功能可以显著减轻服务器的负担,加快页面渲染速度。本文将探讨前端实现图片压缩的几种方法和技术。
用户10501441
2024/11/24
4470
前端实现图片压缩干货分享
# 前端图片压缩方案
先通过 js 中 img 构造函数,实例化 img 对象,后将图片的路径给转移到中,再建立一个 canvas 画布,后对画布进行各方面的数值的设置。
九旬
2023/10/19
3090
你不知道的 Blob
如果你允许用户从你的网站上下载某些文件,那你可能会遇到 Blob 类型。为了实现上述的功能,你可以很容易从网上找到相关的示例,并根据实际需求进行适当的调整。对于部分开发者来说,在完成上述功能之后,他们并不会继续思考 Blob 是什么?
阿宝哥
2020/06/03
4.7K0
面试官昨天问我对base64的理解,着实被问懵了
我们知道一个字节可表示的范围是 0 ~ 255(十六进制:0x00 ~ 0xFF), 其中 ASCII 值的范围为 0 ~ 127(十六进制:0x00 ~ 0x7F);而超过 ASCII 范围的 128~255(十六进制:0x80 ~ 0xFF)之间的值是不可见字符。
用户3806669
2021/03/25
4.8K0
面试官昨天问我对base64的理解,着实被问懵了
在线图片压缩,JS实现图片压缩功能
1. 选择一张图片 const img_original = document.getElementById('img_original'); const img_output = document.getElementById('img_output'); let blob; function preview(file) { let reader = new FileReader(); reader.onload = functio
vivec
2019/08/20
11.5K0
复制粘贴那些事
这篇公众号文章是用typora上写的,这是一款大名鼎鼎的客户端markdown编辑器。
一粒小麦
2019/08/20
2.6K0
复制粘贴那些事
手把手教你实现一个图片压缩工具(Vue与Node的完美配合)
图片压缩对于我们日常生活来讲,是非常实用的一项功能。有时我们会在在线图片压缩网站上进行压缩,有时会在电脑下软件进行压缩。那么我们能不能用前端的知识来自己实现一个图片压缩工具呢?答案是有的。
Vam的金豆之路
2021/12/01
8440
手把手教你实现一个图片压缩工具(Vue与Node的完美配合)
前端图片压缩及上传
图片的上传一般情况下不需要上传大体积的图片,因为如果是用户头像或者是一些要求清晰度不是太高的场景上传大体积图片会很消耗资源,一个是上传耗时比较长,同时也增加了存储的开销,当展示的时候也会消耗下载的带宽,影响加载效率。要求用户上传的图片之前压缩图片很影响用户体验,所以就增加了在前端进行图片压缩的需求。
OECOM
2020/07/02
3.1K0
前端图片压缩及上传
相关推荐
开箱即用的前端图片压缩方案
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验