jquery加载页面的几种方法(页面加载完成就执行)如何去掉css 渐变时的锯齿效果AJAX请求以及解决跨域的问题浅析Vue3动态组件怎么进行异常处理html+css+js写的AI五子棋游戏(附源码)基于jquery 实现导航条高亮显示的两种方法EasyUI使用DataGrid实现动态列数据绑定Vue怎么通过JSX动态渲染组件JS 获取当前日期、时间、星期聊一聊Node.js中的 GC(垃圾回收)机制Ajax 请求队列解决方案并结合elementUi做全局加载状态前端代码风格规范总结JS Generator函数yield表达式示例详解javascript子窗口父窗口相互操作 取值赋值的问题CSS如何实现波浪效果ECharts实现数据超出Y轴最大值max但不隐藏CSS样式穿透的几种方法JavaScript 类型转换CSS 设置页面缩放如何在Vue3+Vite中使用JSXlinux平台下node cnpm的安装方法vue中v-if和v-for的区别是什么详解Vue PC端如何实现扫码登录功能CSS 网格(Grid)布局JavaScript 请求服务端接口Angular开发问题记录:组件拿不到@Input输入属性聊一聊CSS中的盒模型和box-sizing属性vue3.0对服务端进行渲染Web 页面如何实现动画效果移动端 H5 实现拍照功能的几种方法CSS 样式优先级HTML 块级元素、行内元素和行内块级元素深入聊一聊vue3中的reactive()CSS 媒体查询Angular中的路由(Routing)原理怎么移除css的hover事件让交互更加生动!巧用CSS实现鼠标跟随 3D 旋转效果Web页面的几种布局方式JavaScript 评测代码运行速度的几种方法优化jQuery性能的多种方法(整理总结)说一下Vue组件中的自定义事件和全局事件总线列举一下JavaScript中对数组进行合并的几种方法JavaScript 对象合并带你深入了解一下vue.js中的this.$nextTick!如何在JavaScript中对文件进行处理Vue.js 前端项目在常见 Web 服务器上的部署配置vue中$set的实现方法CSS 实现文本装饰效果JavaScript 高阶函数History 和 Hash 路由模式Vue3学习之深度剖析CSS Modules和ScopeCSS 清除浮动CSS 设置背景图片【整理分享】一些常见Vue面试题(附答案解析)CSS里面的transform 属性CSS中的几种尺寸单位总结JavaScript中的条件判断与比较运算uni-app 滚动通知组件的实现JavaScript 执行上下文与作用域前端兼容性问题总结前端性能优化——图片优化JS中数组去重的几种方法JavaScript里实现继承的几种方式JavaScript使用reduce方法实现简单的 i18n 功能JavaScript 日期和时间的格式化大汇总(收集)JS里的原始值与引用值JavaScript 文件处理检测js代码中可能导致内存泄漏的工具Angular学习之ControlValueAccessor接口详解uni-app 日历组件的实现Vue 组件之间传值JavaScript里的回调函数属于闭包吗?JavaScript 解决冒泡事件导致的性能问题总结一下JavaScript中的一些奇怪问题简单说一下JavaScript中的事件冒泡和事件捕获关于 WebpackJavaScript中的循环类型5个实用的TypeScript操作符,助你提升开发能力!HTML img 元素无法显示 base64 图片的可能原因jQuery 遍历方法总结前端性能优化——内存问题javascript中脚本加载和执行机制Web 页面之间传递参数的几种方法解释一下JavaScript中0.1+0.2不等于0.3的问题总结一下JavaScript 中apply、call、bind的使用方法什么是EventLoop?怎么测试Node或页面的性能JavaScript 中 new Date(time).getTime() 获取时间戳方法在 iOS 中的兼容性问题JS里数组合并的几种方法详解vue各种权限控制与管理的实现思路uni-app 弹出层组件的实现用JavaScript实现文件的上传与下载前端性能优化总结简单说一下JavaScript中的事件委托JavaScript如何删除css总结一下JS中的排序算法关于js中的作用域和闭包让页面元素居中的一些方法【javascript算法】二分查找法如何在前端实现上万行大量数据的秒级响应?CSS中父元素被子元素的margin-top影响的解决方法js使用splice方法删除数组元素可能导致的问题如何运行vue项目(超详细图解)js隐式类型转换的副作用了解js的原型和原型链js中的循环引用js判断变量类型的方法web页面最常用的正则校验规则总结js内存管理和垃圾回收js中this关键字的作用和如何改变其上下文JS中的操作符和运算符大总结Vue3 watch 监听对象数组中对象的特定属性总结一下js的浅拷贝和深拷贝JavaScript中的异步编程JavaScript使用一个数组对另一个对象数组进行过滤一个基于Vue3实现的简单日历组件CSS实现磨砂玻璃(毛玻璃)效果样式解决“Vue3调用本地服务接口失败,老是提示下载并安装本地服务”的办法vue3基于组合式API使异步获取的数据对象具有响应性ASP.NET给前端动态添加修改CSS样式JS 标题 关键字在js中如何获取对象的长度了解一下js中的函数式编程Vue框架中监测数组变化的方法VUE html里的文本框只允许输入数字的两种方法分享几种js格式化金额的方法JavaScript的Promise同步处理js中的简写语法JavaScript 面向切面编程(AOP,装饰者模式)了解一下js的跨域问题谈一谈Vue怎么用extend动态创建组件Vue3实现印章徽章组件js中断 forEach 循环的几种方法vue3组件间怎么通信?简述一下通信方式CSS 设置文字间距CSS 网格(Grid)布局Vue3 实现模态框组件js处理扁平数组和树结构相互转换使用Vue和jsmind如何实现思维导图的历史版本控制和撤销/重做功能?Vue.js与ASP.NET的结合,实现企业级应用的开发和部署检查js中的字符串是否可以成为回文Vue.nextTick函数的用法及在异步更新中的应用关于js中0.1+0.2不等于0.3的问题使用JavaScript开发网页地图导航js中如何使用可选函数参数Vue与js的融合,如何编写现代化的前端应用关于Vue与服务器端的通信:如何实现登录鉴权Vue.js的响应式原理如何使用 FabricJS 禁用椭圆的居中旋转?使用JavaScript实现页面滑动切换效果移动端H5页面的缓存问题js里base64与file之间的转换分享一下利用Vue表单处理实现复杂表单布局如何使用CSS创建渐变阴影?如何在 JavaScript 中查看结构体数组?css的弹性布局(Flex布局)Vue统计图表的数据标签和数值显示技巧js实用工具方法库大总结使用Angular和MongoDB来构建具有登录功能的博客应用程序如何在Vue表单处理中实现表单字段的文件下载使用js开发交互式地图应用Vue.component函数的使用及如何创建局部组件css实现三角形的几种方法移动端H5实现自定义拍照界面如何在js中遍历对象jquery如何修改选中状态如何使用js对图像进行压缩js如何计算base64编码图片的大小关于Vue双向数据绑定原理详解Vue.filter函数及如何自定义过滤器列举一下js数组的reduce方法的一些应用如何在Vue表单处理中实现表单的条件渲染vue中的canvas插件js数组的reduce方法的一些应用VUE里使用虚拟DOM来优化更新流程canvas对象有哪些方法js中URL查询字符串(query string)的序列与反序列化如何使用 JavaScript/jQuery 为网站创建暗/亮模式?总结html5中常见的选择器Vue组件开发:工具提示组件的实现方法总结js中常见的层次选择器利用Vue2实现印章徽章组件Vue组件实战:列表组件开发js中如何将对象转换为数组Vue组件开发:地图组件实现方法如何将数据存储到 DOM 中?Vue实战:图片上传组件开发如何使用Vue实现可视化界面设计?vite+TypeScript+vue3+router4+Pinia+ElmPlus+axios+mock项目基本配置Vue组件库推荐:Ant Design Vue深度解析使用Vue实现弹窗效果React Query 数据库插件:与分布式系统的协作指南如何使用vue ui创建vue项目使用CSS的Positions布局打造响应式网页无感刷新页面(附可运行的前后端源码,前端vue,后端node)Css Flex 弹性布局中的换行与溢出处理方法Vue组件库推荐:Element UI深度解析分享一个用HTML、CSS和jQuery构建的漂亮的登录注册界面如何利用React和Sass实现可定制的前端样式如何在Vue中实现拖拽上传文件vue3+TypeScript全局事件总线mitt分享一个Pinia存储的数据持久化插件HTML、CSS和jQuery:实现图片折叠展开的效果如何使用HTML和CSS创建动画条形图?如何利用React和Flutter构建跨平台移动应用用html、css和jQuery实现图片翻页的特效利用Promise优化Vue异步操作的方法CSS Positions布局与网页导航的优化技巧js多图合成一张图CSS3实现动态旋转加载样式使用Velocity.js将动画添加到网页使用FabricJS创建Image对象的JSON表示vue3递归组件---树形组件vue3+TypeScript全局事件总线mitt在Vue中实现可编辑的表格vue3+TypeScript自定义指令:长按触发绑定的函数Vue中如何处理表单数据的双向绑定和验证Vue 简介Vue 安装Vue 常用指令Vue 实例Vue 计算属性Vue 动态样式绑定Vue 事件处理Vue 侦听器Vue 数据双向绑定Vue过渡 & 动画Vue 实例生命周期Vue 插槽的使用Vue 组件基础Vue动态组件 & keep-aliveVue 组件间通信Vue 过滤器Vue 自定义指令Vue 混入 MixinsVue 插件Vue 渲染函数VueRouter 编程式导航VueRouter 路由嵌套VueRouter 基础应用VueRouter 命名视图VueRouter 命名路由Vuex 简介、安装VueRouter 路由传参VueRouter 路由别名、重定向Vuex GetterVuex StateVuex ActionVuex MutationVue-Cli & VueDevTools安装Vuex ModulesVue 第三方库的使用Vue-Cli 项目文件结构分析Vue 本地 Mock 数据Vue 项目打包部署Element 美化 TODO 项目

如何使用js对图像进行压缩

JavaScript 可以使用类似于 canvas 和 web workers 来实现图像压缩。

使用 canvas,可以将图像绘制到 canvas 上,然后使用 canvas 提供的 toBlob() 或 toDataURL() 方法将其转换为不同格式的图像。在这些方法中指定图像质量参数即可实现压缩。

使用 web workers,可以在后台执行图像压缩,以避免阻塞 UI 线程。

但是在浏览器环境下,JavaScript 因为安全限制,不能操作本地文件,所以一般使用在浏览器端上传图片,使用 JavaScript 进行压缩处理,上传到服务端,后续处理。

一、简单压缩

使用 JavaScript 和 canvas 压缩图像可以使用 canvas 的 drawImage() 方法将图像绘制到 canvas 上,然后使用 toDataURL() 方法将图像转换为 Data URL 形式。Data URL 是一种将数据嵌入 URL 的格式,可以在不需要网络请求的情况下直接在浏览器中加载图像。

在调用 toDataURL() 方法时,可以使用第二个参数来指定图像质量。该参数的值应该在 0 到 1 之间,表示图像质量的百分比。0 表示最低质量,1 表示最高质量。

这是一个使用 canvas 和 JavaScript 压缩图像的示例代码:

// 创建 Image 对象
var img = new Image();
img.src = "image.jpg";
img.onload = function () {
  var _this = this;
  // 获取 canvas 元素
  var canvas = document.getElementById("canvas");
  // 绘制图像到 canvas
  canvas.width = img.width;
  canvas.height = img.height;
  var ctx = canvas.getContext("2d");
  ctx.drawImage(_this,img.width,img.height);
  // 使用 toDataURL 方法压缩图像
  var dataUrl = canvas.toDataURL("image/jpeg",0.5);
  // 使用新的 Data URL 更新图像
};

这个例子中,图片会使用 jpeg 格式压缩,质量为 50%,压缩后的图片会被重新赋值回 img.src 里,可以改变其他参数得到不同的压缩效果

二、使用 canvas 将 base64 图像压缩到指定文件大小以内

1、 方法一

1.1、通过循环遍历由大到小的图像质量系数来确定合适的系数

首先使用 canvas 的 drawImage() 方法将图像绘制到 canvas 上,并使用 base64ToBlob() 方法将 base64 图像转换为 Blob 对象。

再检查生成的 Blob 的大小是否超过指定的最大大小。 如果超过,使用不同的图像质量再次压缩图像,直到它的大小小于给定的最大大小为止。

下面是一个示例代码:

var maxSize = 100 * 1024; // 最大文件大小为100KB
var img = new Image();
img.src = "base64 or path";
img.onload = function () {
  const _this = this;
  var canvas = document.createElement("canvas");
  var ctx = canvas.getContext("2d");
  var width = img.width;
  var height = img.height;
  canvas.width = width;
  canvas.height = height;
  ctx.drawImage(_this,width,height);
  var quality = 0.8;
  let newBase64Image,resultBlob;
  do {
    newBase64Image = canvas.toDataURL("image/jpeg",quality);
    resultBlob = base64ToBlob(newBase64Image);
    quality -= 0.1;
  } while (resultBlob.size > maxSize && quality > 0.1);
};

// 将base64 转换为Blob
function base64ToBlob(base64) {
  var arr = base64.split(","),mime = arr[0].match(/:(.*?);/)[1],bstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr],{
    type: mime,});
}

这个示例代码使用 canvas 将 base64 图像压缩到指定的最大文件大小以内。它使用了一个 do-while 循环来不断地减小图像质量直到图像的文件大小符合限制为止。最后它生成了一个 resultBlob 对象,它可以被用来更新页面上的图像或者存储到服务器上。

值得注意的是,这个示例代码中进行图像压缩时的质量是每次减少 0.1,如果压缩后的图像的文件大小仍然超出限制,可能需要调整这个减少量,或者考虑其他压缩策略,比如更改图像的分辨率等。在这个例子中压缩文件大小是每次只减少 0.1,这样可能会花费很长时间,在实际应用中需要根据需求来进行调整。

1.2、通过二分查找算法更快速确定合适的图像质量系数
var maxSize = 100 * 1024; // 最大文件大小为100KB
var img = new Image();
img.src = "base64 or path";
img.onload = function () {
  const _this = this;
  var canvas = document.createElement("canvas");
  var ctx = canvas.getContext("2d");
  var width = img.width;
  var height = img.height;
  canvas.width = width;
  canvas.height = height;
  ctx.drawImage(_this,height);
  var quality = 0.8;
  let newBase64Image = canvas.toDataURL("image/jpeg",quality);
  let fileSize = getBase64ImageSize(newBase64Image);
  if (fileSize > maxSize) {
    const qualityArr = [],step = 0.01;
    for (let i = step; i <= quality; i += step) {
      // qualityArr.push(parseFloat(i.toFixed(2)));
      qualityArr.push(parseFloat(i));
    }
    let left = 0,right = qualityArr.length - 1;
    do {
      const mid = Math.floor((left + right) / 2);
      newBase64Image = canvas.toDataURL("image/jpeg",qualityArr[mid]);
      fileSize = getBase64ImageSize(newBase64Image);
      if (fileSize > maxSize) {
        right = mid - 1;
      } else {
        left = mid + 1;
      }
    } while (left <= right);
  }
};

// 计算base64编码图片大小
function getBase64ImageSize(base64) {
  const indexBase64 = base64.indexOf("base64,");
  if (indexBase64 < 0) return -1;
  const str = base64.substr(indexBase64 + 6);
  // 大小单位:字节
  return (str.length * 0.75).toFixed(2);
}

该方法由  @Wuya 提出的建议进行改进。

2.、方法二:递归代替迭代(do-while 循环)

递归方式可避免迭代导致压缩处理过程中,页面提示组件无法显示的问题

2.1、递归遍历递减图像质量系数确定合适的系数
// 计算base64编码图片大小
function getBase64ImageSize(base64) {
  const indexBase64 = base64.indexOf("base64,");
  if (indexBase64 < 0) return -1;
  const str = base64.substr(indexBase64 + 6);
  // 大小单位:字节
  return (str.length * 0.75).toFixed(2);
}

/**
 * 	图像压缩,默认同比例压缩
 * @param {Object} imgPath
 *	图像base64编码字符串或图像可访问路径
 * @param {Object} obj
 *	obj 对象 有 width, height, quality(0-1)
 * @param {Object} maxSize
 *	指定压缩后的文件大小,单位:字节
 * @param {Object} callback
 *	回调函数有一个参数,base64的字符串数据
 */
function compressedImage(path,obj,maxSize,callback) {
  let img = new Image();
  img.src = imgPath;
  img.onload = function () {
    const _this = this;
    // 默认按比例压缩
    let w = _this.width,h = _this.height,scale = w / h;
    w = obj.width || w;
    h = (obj.height && obj.height * (w / scale)) || h;
    // 生成canvas
    let canvas = document.createElement("canvas");
    let ctx = canvas.getContext("2d");
    canvas.width = w;
    canvas.height = h;
    ctx.drawImage(_this,w,h);
    // 图像质量,默认图片质量为0.8
    let quality = 0.8;
    if (obj.quality && obj.quality > 0 && obj.quality <= 1) {
      quality = obj.quality;
    }
    // quality值越小,所绘制出的图像越模糊
    let newBase64Image = canvas.toDataURL("image/jpeg",quality);
    let fileSize = getBase64ImageSize(newBase64Image);
    if (fileSize > maxSize && quality > 0.01) {
      if (quality > 0.05) {
        quality = quality - 0.05;
      } else {
        quality = 0.01;
      }
      compressedImage(
        imgPath,{
          quality: quality,},callback
      );
      return;
    }
    if (!!callback) {
      // 回调函数返回压缩后的 base64 图像
      callback(newBase64Image);
    }
  };
}
2.2、递归二分查找确定图像质量系数(由 2.1 进行改进),并增加宽高压缩率(最终完整版,推荐)
// 计算 base64 编码图片大小
function getBase64ImageSize(base64) {
  const indexBase64 = base64.indexOf("base64,");
  if (indexBase64 < 0) return -1;
  const str = base64.substr(indexBase64 + 6);
  // 大小单位:字节
  return (str.length * 0.75).toFixed(2);
}

/**
 * 	图像压缩,默认同比例压缩
 * @param {Object} imgPath
 *	图像 base64 编码字符串或图像可访问路径
 * @param {Object} compParamObj
 *	压缩参数,compParamObj 对象的属性:width-宽,height-高,
 *  ratio(0-1)-宽高压缩率,quality(0-1)-图像质量系数
 * @param {Object} maxSize
 *	指定压缩后的文件大小,单位:字节
 * @param {Object} callback
 *	回调函数有一个参数,base64 的字符串数据
 * @param {Object} left
 *	二分递归查找 left
 * @param {Object} right
 *	二分递归查找 right
 * @param {Object} oQuality
 *	初始图像质量系数
 */
function compressedImage(
  imgPath,compParamObj,callback,left = 0,right = null,oQuality = null
) {
  let img = new Image();
  img.src = imgPath;
  img.onload = function () {
    const _this = this;
    // 默认按比例压缩
    let w = _this.width * (compParamObj?.ratio || 1),h = _this.height * (compParamObj?.ratio || 1),scale = w / h;
    w = compParamObj.width || w;
    h = (compParamObj.height && compParamObj.height * (w / scale)) || h;
    // 生成 canvas
    let canvas = document.createElement("canvas");
    let ctx = canvas.getContext("2d");
    canvas.width = w;
    canvas.height = h;
    ctx.drawImage(_this,h);
    // 图像质量系数,默认图片质量为 0.8
    let quality = 0.8;
    if (
      compParamObj.quality &&
      compParamObj.quality > 0 &&
      compParamObj.quality <= 1
    ) {
      quality = compParamObj.quality;
    }
    // quality 值越小,所绘制出的图像越模糊
    let newBase64Image = canvas.toDataURL("image/jpeg",quality);
    let fileSize = getBase64ImageSize(newBase64Image);

    if (left <= right) {
      if (oQuality === null) {
        oQuality = quality;
      }

      const qualityArr = [],step = 0.01;
      for (let i = step; i <= oQuality; i += step) {
        qualityArr.push(parseFloat(i));
      }

      if (right === null) {
        right = qualityArr.length;
      }

      const mid = Math.floor((left + right) / 2);

      if (fileSize > maxSize) {
        compressedImage(
          imgPath,{
            quality: qualityArr[mid],// 设置宽高压缩率对图像进行宽高压缩,降低图像被压缩后出现彩虹斑的情况
            ratio: 0.5,left,mid - 1,oQuality
        );
      } else {
        compressedImage(
          imgPath,mid + 1,right,oQuality
        );
      }
      return;
    }
    if (!!callback) {
      // 回调函数返回压缩后的 base64 图像
      callback(newBase64Image);
    }
  };
}

上述代码中,当只通过图像质量系数 oQuality 对图像进行压缩时,图像文件越大,被压缩后出现的彩虹斑的概率越高,因此,为降低图像被压缩后出现彩虹斑的情况,同时设置宽高压缩率对图像宽高进行压缩。

三、使用 canvas 和 web workers 来实现图像压缩

JavaScript 的 Web Workers API 允许在浏览器中创建多个线程,可以在后台线程中执行 JavaScript 代码,而不会影响主线程的响应性。因此,可以使用 Web Workers 来执行计算密集型任务,例如图像压缩。

下面是一个简单的示例代码,展示了如何使用 Web Workers 在后台线程中执行图像压缩:

// 在主线程中
var worker = new Worker("worker.js");
worker.onmessage = function (e) {
  var compressedImage = e.data;
  // do something with compressedImage
};
worker.postMessage({
  image: base64Image,maxSize: 100 * 1024,// 最大文件大小为100KB
});
// worker.js
self.onmessage = function (e) {
  var image = e.data.image;
  var maxSize = e.data.maxSize;
  var img = new Image();
  img.src = image;
  img.onload = function () {
    var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");
    var width = img.width;
    var height = img.height;
    canvas.width = width;
    canvas.height = height;
    ctx.drawImage(img,height);
    var quality = 0.8;
    let newBase64Image,resultBlob;
    do {
      // 该方法是异步获取 Blob 的,导致无法及时获取 resultBlob.size
      // canvas.toBlob(function (blob) {
      //     resultBlob = blob;
      //     self.postMessage(resultBlob);
      // },'image/jpeg',quality);

      newBase64Image = canvas.toDataURL("image/jpeg",quality);
      resultBlob = base64ToBlob(newBase64Image);
      self.postMessage(resultBlob);
      quality -= 0.1;
    } while (resultBlob.size > maxSize && quality > 0.1);
  };
};

// 将 base64 转换为 Blob
function base64ToBlob(base64) {
  var arr = base64.split(",});
}

这个示例代码中,在主线程中通过创建一个 Worker 对象并加载一个 worker.js 文件来启动一个后台线程. 在 worker.js 中,我们在 onmessage 中定义了图像压缩的逻辑,并使用 postMessage 来将压缩后的图像发送回主线程。这样做的优点在于,将图像压缩的计算密集型任务放到了后台线程中进行,可以保证主线程的响应性不会受到影响。这样能够避免因为计算密集型任务而导致页面卡顿或延迟。

需要注意的是,Web Workers 不能直接访问 DOM,所以需要使用 postMessage 在主线程和后台线程之间传递数据。

这只是一个简单的示例,实际应用中可能需要根据需求进行更多的定制。

四、使用第三方库进行图像压缩

在 JavaScript 中进行图像压缩有一些第三方库可供使用,比如:

  • canvas-toBlob.js:在不支持 toBlob() 的浏览器中提供对 toBlob() 的支持。
  • lwip:一个 JavaScript 的图像处理库,可以实现图像的压缩,旋转,裁剪等操作,可在 Node.js 环境中使用。
  • browser-image-resizer:基于 canvas 和 web workers 的 JavaScript 图像压缩库。
  • jpeg-js:使用 JavaScript 实现的 JPEG 压缩库,可以在浏览器或 Node.js 环境中使用。

使用这些库进行压缩时需要注意的是,它们在性能上可能有所限制。对于大型图像,压缩可能需要相当长的时间。可能需要在用户上传图像时显示加载条或消息,以提醒用户正在进行压缩。

五、使用 Canvas 进行图像压缩时,出现彩虹斑问题

在使用 Canvas 进行图像压缩时,可能会出现彩虹斑问题,这通常是由于压缩算法中使用了量化方法而导致的,量化会使颜色变得不连续,从而产生彩虹斑。

以下是一些可以尝试的解决方法:

  • 调整图像宽高,尝试对图像的宽高进行等比例缩放。

  • 使用 WebP 格式进行压缩。WebP 格式使用有损压缩,但可以在保持较高质量的同时减少文件大小。

  • 尝试使用更高质量的压缩算法。如果正在使用默认的算法,请尝试使用更高质量的算法进行压缩。

  • 调整颜色空间。尝试将颜色空间更改为 sRGB,这可以减少量化的影响。

  • 减少图像的色深。尝试将图像的色深降低到较低的级别,这可以减少量化的影响。

  • 使用 dithering(抖动)技术。抖动技术可以在颜色变化较大的区域添加噪声,从而减少彩虹斑的出现。

  • 增加图像的分辨率。尝试将图像的分辨率增加到较高的级别,这可以减少量化的影响。

  • 调整图像的亮度和对比度。在某些情况下,调整图像的亮度和对比度可以减少彩虹斑的出现。

  • 在绘制到 Canvas 之前先进行色彩空间转换。例如,将图像转换为 YUV 色彩空间,这可以减少量化引起的问题。

需要注意的是,以上解决方法并不一定适用于所有情况,具体取决于图像的特点和要求。使用这些方法可能会影响图像的视觉质量,需要在权衡文件大小和视觉质量之间做出选择。

六、使用 Canvas 进行图像压缩时,出现传入不同的图像质量系数 quality,生成的 base64 字符串却不变的情况

通过上述压缩方法进行图像压缩时,在 quality 参数一定范围内,以 0.05 递减 quality 参数,同时对 quality 进行保留两位小数处理后再传入 toDataURL 方法进行压缩时,存在生成的 base64 的大小一直不变,也就是 base64 字符串不变,产生该现象具体原因不详。

现象如图:

  • 对 quality 进行保留两位小数处理

说明:图中 base64 码只取前 1000 个字符作为对比。

  • 未对 quality 进行小数处理