返回顶部
首页 > 资讯 > 前端开发 > JavaScript >JS前端图片最优化压缩方案
  • 381
分享到

JS前端图片最优化压缩方案

2024-04-02 19:04:59 381人浏览 泡泡鱼
摘要

目录前言压缩图片思考压缩图片基本流程准备htmlcanvasElement.toDataURL()语法参数猜想实践结论附录优化升级优化升级 TS新写法前言 上传图片/视频/文件是我们

前言

上传图片/视频/文件是我们经常会遇到的问题,但是一旦图片过大就会导致不好的操作体验。 图片上传是前端中常见的的业务场景。无论是前台还是后台,适当的对图片进行压缩处理, 可以显著的提升用户体验。

而在后台管理系统中,图片压缩不仅仅能够提升后台管理员操作体验,更是可以防止后台设置过大的图片导致前台图片加载过久,从而影响用户体验。

压缩图片思考

压缩图片基本流程

  • 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/jpeg 或 image/WEBp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。 Chrome支持“image/webp”类型。

猜想

可能toDataURL(type,quality)的第二个参数(quality)越小,文件体积越小

实践

先看下原图信息大小是7.31kb

toDataURL(type,quality)quality默认0.92看看压缩结果如何

<input id="fileInput" type="file" />
<img id="img" src="" alt="">
let fileId = document.getElementById('fileInput')
let img = document.getElementById('img')
fileId.onchange = function (e) {
  let file = e.target.files[0]
  compressImg(file, 0.92).then(res => {//compressImg方法见附录
    console.log(res)
    img.src = window.URL.createObjectURL(res.file);
  })
}

compressImg方法见附录

可以看到图片大小为8.83kb压缩后图片反而变大了,这是怎么回事?

看来起初的猜想不完全正确,咱们继续看看。

fileId.onchange = function (e) {
  let file = e.target.files[0]
  compressImg(file, 0.1).then(res => {//compressImg方法见附录
    console.log(res)
    img.src = window.URL.createObjectURL(res.file);
  })
}

quality为0.1的时候,图片仅有1.63kb,同样的质量也下降了

继续......A long time later

咱们用折线图来看吧更直观

我又拿了几个图片让他们使用默认值0.92,结果都比原图大

所以说默认值得到的图片往往比原图大

下面看看当quality为多少时对图片的压缩效率可以最大化

压缩效率最大化,即:在不影响图片质量的情况下最大化压缩 尝试了一系列的图片之后我发现 当quality在0.2~0.5之间,图片质量变化并不大,quality的值越小,压缩效率越可观(也就是在0.2左右时,压缩图片可以最大化,同时并不对图片质量造成太大影响)

结论

经过实践,可以得出结论这个默认值得到的图片往往比原图的图片质量要高。

quality在0.2~0.5之间,图片质量变化并不大,quality的值越小,压缩效率越可观(也就是在0.2左右时,压缩图片可以最大化,同时并不对图片质量造成太大影响)

附录


function compressImg(file, quality) {
  if (file[0]) {
    return Promise.all(Array.from(file).map(e => compressImg(e,
      quality))) // 如果是 file 数组返回 Promise 数组
  } else {
    return new Promise((resolve) => {
      const reader = new FileReader() // 创建 FileReader
      reader.onload = ({
        target: {
          result: src
        }
      }) => {
        const image = new Image() // 创建 img 元素
        image.onload = async () => {
          const canvas = document.createElement('canvas') // 创建 canvas 元素
          canvas.width = image.width
          canvas.height = image.height
          canvas.getContext('2d').drawImage(image, 0, 0, image.width, image.height) // 绘制 canvas
          const canvasURL = canvas.toDataURL('image/jpeg', quality)
          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({
            file: miniFile,
            origin: file,
            beforeSrc: src,
            afterSrc: canvasURL,
            beforeKB: Number((file.size / 1024).toFixed(2)),
            afterKB: Number((miniFile.size / 1024).toFixed(2))
          })
        }
        image.src = src
      }
      reader.readAsDataURL(file)
    })
  }
}

优化升级

使用过程中发现边界问题,即图片尺寸过大、 iOS 尺寸限制,png 透明图变黑等问题

所以优化了大尺寸图片等比例缩小,这极大的提高了压缩效率

举个栗子,以一张大小14M,尺寸6016X4016的图片为例

一个14M的原图(6016X4016)不改变质量只改变尺寸的前提下压缩后(1400X935)就剩139.62KB

可想而知,尺寸的限制能最大化提高压缩效率

  
  compressImg(file, quality) {
    var qualitys = 0.52
    console.log(parseInt((file.size / 1024).toFixed(2)))
    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 => this.compressImg(e,
        qualitys))) // 如果是 file 数组返回 Promise 数组
    } else {
      return new Promise((resolve) => {
        console.log(file)
        if ((file.size / 1024).toFixed(2) < 300) {
          resolve({
            file: file
          })
        } else {
          const reader = new FileReader() // 创建 FileReader
          reader.onload = ({
            target: {
              result: src
            }
          }) => {
            const image = new Image() // 创建 img 元素
            image.onload = async() => {
              const canvas = document.createElement('canvas') // 创建 canvas 元素
              const context = canvas.getContext('2d')
              var targetWidth = image.width
              var targetHeight = image.height
              var originWidth = image.width
              var originHeight = image.height
              if (1 * 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))
                  }
                }
              }
              canvas.width = targetWidth
              canvas.height = targetHeight
              context.clearRect(0, 0, targetWidth, targetHeight)
              context.drawImage(image, 0, 0, targetWidth, targetHeight) // 绘制 canvas
              const canvasURL = canvas.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'
              })
              console.log({
                file: miniFile,
                origin: file,
                beforeSrc: src,
                afterSrc: canvasURL,
                beforeKB: Number((file.size / 1024).toFixed(2)),
                afterKB: Number((miniFile.size / 1024).toFixed(2)),
                qualitys: qualitys
              })
              resolve({
                file: miniFile,
                origin: file,
                beforeSrc: src,
                afterSrc: canvasURL,
                beforeKB: Number((file.size / 1024).toFixed(2)),
                afterKB: Number((miniFile.size / 1024).toFixed(2))
              })
            }
            image.src = src
          }
          reader.readAsDataURL(file)
        }
      })
    }
  },

优化升级 TS新写法

最近很多小伙伴在问我有没有TS版本的,今天刚好弄了下这一块,稍微调整了下,相较于之前更加简洁,性能也快了不少;

如果需要对尺寸压缩,请自行添加尺寸处理方法,也很简单,自行添加吧,方法写的很简洁明了了,就不多加赘述了,大家自取吧。

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))
}

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
}

以上就是js前端图片最优化压缩方案的详细内容,更多关于JS前端图片压缩的资料请关注编程网其它相关文章!

--结束END--

本文标题: JS前端图片最优化压缩方案

本文链接: https://lsjlt.com/news/167662.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • JS前端图片最优化压缩方案
    目录前言压缩图片思考压缩图片基本流程准备HTMLCanvasElement.toDataURL()语法参数猜想实践结论附录优化升级优化升级 TS新写法前言 上传图片/视频/文件是我们...
    99+
    2024-04-02
  • Android性能优化(六)图片压缩
    一、压缩图片 文件压缩——内存压缩 二、文件压缩方式 1.质量压缩   2.尺寸压缩   3.格式选择:JPEG/WEBP (4.0以上) 三、压缩原理 /frameworks...
    99+
    2022-06-06
    压缩 图片 优化 图片压缩 Android
  • element前端实现压缩图片的功能
    目录前言实现效果实现步骤前言 随着现在手机像素,拍照功能越来越好,随之而来的是本地图片越来越大,那么如何更好的将本地图片上传到后端接口呢?这是后台管理系统常见的场景和头疼的问题,这里...
    99+
    2023-03-01
    element 压缩图片 vue 压缩图片
  • element前端如何实现压缩图片功能
    这篇文章主要讲解了“element前端如何实现压缩图片功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“element前端如何实现压缩图片功能”吧!实现效果如下图所示,从 580kb -&g...
    99+
    2023-07-05
  • js前端图片加载异常兜底方案
    目录背景<img>加载错误解决方案内联事件全局img添加事件利用error事件捕获替换src方式的最优解CSS处理的最优解<img>加载超时解决方案嗅探切换D...
    99+
    2024-04-02
  • Android性能优化之图片大小,尺寸压缩综合解决方案
    目录前言常见的图片压缩方法质量压缩尺寸压缩libjpeg图片压缩流程总结前言 在Android中我们经常会遇到图片压缩的场景,比如给服务端上传图片,包括个人信息的用户头像,有时候人脸...
    99+
    2024-04-02
  • web前端中如何优化图片
    这篇文章给大家介绍web前端中如何优化图片,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。对于在网站优化时,图片也是要得优化的。随着互联网搜索技术的发展,以往不能被搜索引擎“读懂”的图片...
    99+
    2024-04-02
  • PHP开发中如何优化图片压缩和优化加载
    摘要:在网站中,图片是让用户获得更直观和有吸引力的体验的重要元素。然而,图片文件通常较大,加载速度较慢,会影响网站的性能和用户的体验。本文将详细介绍如何使用PHP开发来优化图片压缩和优化加载的方法,并提供具体的代码示例。请注意:本文所使用的...
    99+
    2023-10-21
    PHP开发 图片压缩 加载优化
  • js如何实现移动端图片压缩上传功能
    这篇文章给大家分享的是有关js如何实现移动端图片压缩上传功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。移动端图片压缩上传功能如何实现?做移动端开发的时候,form里面的fil...
    99+
    2024-04-02
  • JS+HTML图片显示Canvas压缩功能的方法
    这篇文章主要介绍了JS+HTML图片显示Canvas压缩功能的方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一.选择图片并显示<!...
    99+
    2024-04-02
  • Linux下怎么压缩和优化jpg与png图片
    这篇文章主要介绍“Linux下怎么压缩和优化jpg与png图片”,在日常操作中,相信很多人在Linux下怎么压缩和优化jpg与png图片问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux下怎么压缩和优化...
    99+
    2023-06-12
  • java怎么实现1M图片压缩优化到100kb
    这篇“java怎么实现1M图片压缩优化到100kb”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“java怎么实现1M图片压缩...
    99+
    2023-07-02
  • WEB前端优化必备压缩工具YUI-compressor详解
    YUI Compressor(YUI压缩器)是一个用于压缩和混淆JavaScript和CSS文件的工具。它由雅虎公司开发,并且是一个...
    99+
    2023-09-14
    WEB前端
  • Android性能优化之图片大小,尺寸压缩的方法
    这篇文章主要介绍“Android性能优化之图片大小,尺寸压缩的方法”,在日常操作中,相信很多人在Android性能优化之图片大小,尺寸压缩的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android性能...
    99+
    2023-06-30
  • PHP开发中如何优化图片压缩和优化加载速度
    随着互联网的快速发展,图片成为了网页设计和内容展示中不可或缺的一部分。然而,过大的图片文件不仅会占用用户的存储空间,还会增加网页加载时间,降低用户体验。为了提升网站的性能和用户体验,我们可以通过优化图片压缩和加载速度来改进网站加载速度。图片...
    99+
    2023-10-21
    优化 图片压缩 加载速度
  • Android中图片压缩方案详解及源码下载
    Android中图片压缩方案详解及源码下载 图片的展示可以说在我们任何一个应用中都避免不了,可是大量的图片就会出现很多的问题,比如加载大图片或者多图时的OOM问题,可以移步到A...
    99+
    2022-06-06
    压缩 源码下载 图片 图片压缩 源码 Android
  • java实现1M图片压缩优化到100kb实现示例
    目录引言一、图像压缩二、Java数字图像处理三、图像压缩实战四、其他开源库五、一点点心声引言 坦白从宽吧,我就是那个花了两天两夜把 1M 图片优化到 100kb 的家伙—...
    99+
    2024-04-02
  • web前端图片压缩、方向纠正、预览、上传插件的方法是什么
    这篇文章主要讲解了“web前端图片压缩、方向纠正、预览、上传插件的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“web前端图片压缩、方向纠正、预览...
    99+
    2024-04-02
  • 前端vue-cropperjs实现图片裁剪方案
    目录引言图片裁剪图片裁剪的流程vue-cropperjs的使用代码实现实现效果v-viewer的使用代码实现实现效果最后引言 做了个图片的裁剪的功能和预览的功能,前端图片的裁剪方案,...
    99+
    2024-04-02
  • Android Fresco图片加载优化的方案
    目录优化背景数据记录优化方案注意事项优化背景 一般情况下,Fresco图片加载需使用SimpleDraweeView,这个控件并不能自动根据自身的尺寸按需加载图片,即一个 N×N ...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作