前端的图片压缩image-compressor(可在图片上传前实现图片压缩)

image-compressor

一个简单的JavaScript图像压缩器。使用浏览器的原生canvas.toBlob API做的压缩工作。一般使用此压缩是在客户端图像文件上传之前。

实例模板:Website
github:image-compressor

Getting started(新手入门)

Install(npm 安装)

npm install image-compressor.js // 注意是image-compressor.js 不是 image-compressor那是另一个包

Usage(使用)

Syntax语法
new ImageCompressor([file[, options]])
参数说明

file:(可选)压缩的目标图像文件,类型是 File 或者 Blob
options:(可选)压缩选项,类型是 Object

案例

<input type="file" id="file" accept="image/*">
import axios from 'axios'
import ImageCompressor from 'image-compressor.js' // 引入

document.getElementById('file').addEventListener('change', (e) => {
  const file = e.target.files[0]; // file对象
  if (!file) { return } // 为空处理
  new ImageCompressor(file, {
    quality: .6,
    success(result) {
      const formData = new FormData(); // FormData学习地址 https://developer.mozilla.org/zh-CN/docs/Web/API/FormData
      formData.append('file', result, result.name);

      // 通过XMLHttpRequest服务发送压缩的图像文件-Send the compressed image file to server with XMLHttpRequest.
      axios.post('/path/to/upload', formData).then(() => {
        console.log('Upload success');
      });
    },
    error(e) {
      console.log(e.message);
    },
  });
});

Options参数

checkOrientation

是否检查图片的 orientation 属性,类型是 boolean。默认值是 true。

提示:如果读取图像的EXIF的 orientation 属性(JPEG图像),有可能根据 orientation 属性自动翻转或旋转图像。
注意:不要一直相信这一点,因为一些JPEG图像有不正确的(不是标准的) orientation 属性

maxWidth

输出图像的最大宽度,类型是 number。默认值是 Infinity。值应该大于0。

因为一个canvas元素的大小限制,所以为了避免得到一个空白的输出图像,你可能需要给最大宽度和最大高度选项设置有限的数字。

maxHeight

输出图像的最大高度,类型是 number。默认值是 Infinity。值应该大于0。

minWidth

输出图像的最小宽度,类型是 number。默认值是 0。该值应大于0且不应大于maxWidth

minHeight

输出图像的最小宽度,类型是 number。默认值是 0。该值应大于0且不应大于maxHeight

width

输出图像的宽度,类型是 number。默认值是 undefined。值应该大于0。

如果没有指定,将使用原始图像的自然宽度,或者如果设置高度选项,则宽度将由自然长宽比自动计算。

height

输出图像的高度,类型是 number。默认值是 undefined。值应该大于0。

如果没有指定,将使用原始图像的自然高度,或者如果设置宽度选项,则高度将由自然长宽比自动计算。
注意:为了保持与原始图像相同的宽高比,如果设置宽度选项,将使用它自动计算高度,这意味着高度选项将被忽略。

quality

输出图像的画质,类型是 number。默认值是 undefined。值是0到1之间的数字。

小心使用1,因为它可能使输出图像的尺寸变大。
注意:此选项仅适用于 JPEG 和 WebP 格式的图像。

Examples:

图片原来大小 图片压缩大小 压缩比例 描述
0 2.12MB 114.61 KB 94.72% -
0.2 2.12MB 349.57 KB 83.90% -
0.4 2.12MB 517.10 KB 76.18% -
0.6 2.12MB 694.99 KB 67.99% 推荐
0.8 2.12MB 1.14 MB 46.41% 推荐
1 2.12MB 2.12 MB 0% 不推荐
NaN 2.12MB 2.01 MB 5.02% -

mimeType

输出图像的文件类型,类型是 string。默认值是 auto。默认情况下,源映像文件的原始MIME类型将被使用。

convertSize

输出图像的文件类型,类型是 number。默认值是 5000000 (5MB)。

PNG文件超过此值将被转换为JPEG格式。若要禁用此功能,只需将值设置为无穷大。

Examples (in Chrome 61):

convertSize 输入的文件大小Input size (type) 输出的文件大小Output size (type) 压缩比
5 MB 1.87 MB (PNG) 1.87 MB (PNG) 0%
5 MB 5.66 MB (PNG) 450.24 KB (JPEG) 92.23%
5 MB 9.74 MB (PNG) 883.89 KB (JPEG) 91.14%

beforeDraw(context, canvas)

在将图像绘制到画布中进行压缩之前,要执行的钩子函数,类型是 Function。默认值是 null。
参数说明:

context: canvas的2D渲染上下文。
canvas: 压缩画布

new ImageCompressor(file, {
  beforeDraw(context) {
    context.fillStyle = '#fff';
  },
});

drew(context, canvas)

该钩子函数执行后,将图像绘制到画布中进行压缩,类型是 Function。默认值是 null。
参数说明:

context: canvas的2D渲染上下文。
canvas: 压缩画布

new ImageCompressor(file, {
  drew(context) {
    context.filter = grayscale(100%);
  },
});

success(result)

成功压缩图像时执行的钩子函数,类型是 Function。默认值是 null。
参数说明:

result: 压缩后的图像(一个Blob对象)。

error(err)

当图像压缩失败时执行的钩子函数,类型是 Function。默认值是 null。
参数说明:

err: 压缩错误(一个Error对象)。

方法

compress(file[, options])

file:(必选)压缩的目标图像文件,类型是 File 或者 Blob
options:(可选)压缩选项,类型是 Object
返回值: Promise

使用:

const imageCompressor = new ImageCompressor();

imageCompressor.compress(e.target.files[0], {
    quality: 0.8,
    maxHeight: 1000,
    maxWidth: 1000
}).then((result) => { // 压缩成功的回调 Handle the compressed image file.
    const formData = new FormData()
    formData.append('file', result)
    // 请求:Send the compressed image file to server with XMLHttpRequest...
    // var xhr = new XMLHttpRequest()
    // xhr.withCredentials = true...
}).catch((err) => { // 压缩失败的回调 Handle the error
    console.log(err)
})

浏览器支持

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Opera (latest)
  • Edge (latest)
  • Internet Explorer 10+ (requires a Promise polyfill as es6-promise)

案例

基于vue的element-ui图片上传前的压缩,注意是element-ui的上传组件。

首先:

npm install image-compressor.js

然后:

import ImageCompressor from 'image-compressor.js' // 引入图片压缩

构写代码:

html

<el-upload  :httpRequest="httpRequest"></el-upload>

httpRequest

httpRequest (options) { // 覆盖默认的上传行为,可以自定义上传的实现,解决压缩问题
  if (this.imageCompress && this.acceptName === 'image/*') { // 如果允许压缩,并且当前上传的是图片
    var imageCompressor = new ImageCompressor() // 压缩成功则使用压缩的结果,不成功直接上传
    imageCompressor.compress(options.file, {
      quality: 0.8,
      maxHeight: 1000,
      maxWidth: 1000
    }).then((result) => { // 压缩成功的回调
      options.file = result
      console.log(options)
      return ajax(options) // 压缩成功把压缩成功的数据传递给ajax.js
    }).catch((err) => { // 压缩失败的回调
      console.log(err)
      return options.file // 压缩失败把原文件传递
    })
  } else {
    return ajax(options)
  }
}

ajax.js

使用说明:ajax.js可以拿出来单独使用哟!如果需要封装成引用型组件,请自行封装。

function getError (action, option, xhr) {
  let msg
  if (xhr.response) {
    msg = `${xhr.response.error || xhr.response}`
  } else if (xhr.responseText) {
    msg = `${xhr.responseText}`
  } else {
    msg = `fail to post ${action} ${xhr.status}`
  }

  const err = new Error(msg)
  err.status = xhr.status
  err.method = 'post'
  err.url = action
  return err
}

function getBody (xhr) {
  const text = xhr.responseText || xhr.response
  if (!text) {
    return text
  }

  try {
    return JSON.parse(text)
  } catch (e) {
    return text
  }
}

export default function upload (option) {
  if (typeof XMLHttpRequest === 'undefined') {
    return
  }

  const xhr = new XMLHttpRequest()
  const action = option.action

  if (xhr.upload) {
    xhr.upload.onprogress = function progress (e) {
      if (e.total > 0) {
        e.percent = e.loaded / e.total * 100
      }
      option.onProgress(e)
    }
  }

  const formData = new FormData()

  if (option.data) {
    Object.keys(option.data).forEach(key => {
      formData.append(key, option.data[key])
    })
  }

  formData.append(option.filename, option.file)

  xhr.onerror = function error (e) {
    option.onError(e)
  }

  xhr.onload = function onload () {
    if (xhr.status < 200 || xhr.status >= 300) {
      return option.onError(getError(action, option, xhr))
    }

    option.onSuccess(getBody(xhr))
  }

  xhr.open('post', action, true)

  if (option.withCredentials && 'withCredentials' in xhr) {
    xhr.withCredentials = true
  }

  const headers = option.headers || {}

  for (let item in headers) {
    if (headers.hasOwnProperty(item) && headers[item] !== null) {
      xhr.setRequestHeader(item, headers[item])
    }
  }
  xhr.send(formData)
  return xhr
}

结语

到此我们学会了使用image-compressor.js进行图片压缩,并且可以根据image-compressor.js在图片上传前实现图片压缩。

提示:后面还有精彩敬请期待,请大家关注我的专题:web前端。如有意见可以进行评论,每一条评论我都会认真对待。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,157评论 2 33
  • HTML 5 HTML5概述 因特网上的信息是以网页的形式展示给用户的,因此网页是网络信息传递的载体。网页文件是用...
    阿啊阿吖丁阅读 3,875评论 0 0
  • (10)绘忆真体验 “你喜欢听什么歌?”毛不易问余暖。 “心动”余暖想了一会儿还是说了出来,这确实是自己最喜欢的歌...
    小鱼稚阅读 229评论 0 1
  • 历史,是胜利者书写的。 但是,在司马迁的史记里,依然把项羽写在本纪里边。 要知道,本纪是专属于帝王的传记。司马迁是...
    成成日志阅读 394评论 0 0