19

Vue 图片压缩并上传至服务器

 4 years ago
source link: https://juejin.im/post/5e1e8129e51d453cee48cd8b
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文主要讲解基于 Vue + Vant ,实现移动端图片选择,并用 Canvas 压缩图片,最后上传至服务器。还会封装一个工具类,方便直接调用。

一、工具类封装

废话不多说先上代码,封装一个 CompressImageUtils 工具类:

/**
 * 图片压缩工具类
 * 最大高度和最大宽度都为 500,如果超出大小将等比例缩放。
 *
 * 注意可能出现压缩后比原图更大的情况,在调用的地方自己判断大小并决定上传压缩前或压缩后的图到服务器。
 */

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


// 压缩图片
export function compressImage(path) {

  //最大高度
  const maxHeight = 500;
  //最大宽度
  const maxWidth = 500;

  return new Promise((resolve, reject) => {
    let img = new Image();
    img.src = path;
    img.onload = function () {
      const originHeight = img.height;
      const originWidth = img.width;
      let compressedWidth = img.height;
      let compressedHeight = img.width;
      if ((originWidth > maxWidth) && (originHeight > maxHeight)) {
        // 更宽更高,
        if ((originHeight / originWidth) > (maxHeight / maxWidth)) {
          // 更加严重的高窄型,确定最大高,压缩宽度
          compressedHeight = maxHeight
          compressedWidth = maxHeight * (originWidth / originHeight)
        } else {
          //更加严重的矮宽型, 确定最大宽,压缩高度
          compressedWidth = maxWidth
          compressedHeight = maxWidth * (originHeight / originWidth)
        }
      } else if (originWidth > maxWidth && originHeight <= maxHeight) {
        // 更宽,但比较矮,以maxWidth作为基准
        compressedWidth = maxWidth
        compressedHeight = maxWidth * (originHeight / originWidth)
      } else if (originWidth <= maxWidth && originHeight > maxHeight) {
        // 比较窄,但很高,取maxHight为基准
        compressedHeight = maxHeight
        compressedWidth = maxHeight * (originWidth / originHeight)
      } else {
        // 符合宽高限制,不做压缩
      }
      // 生成canvas
      let canvas = document.createElement('canvas');
      let context = canvas.getContext('2d');
      canvas.height = compressedHeight;
      canvas.width = compressedWidth;
      context.clearRect(0, 0, compressedWidth, compressedHeight);
      context.drawImage(img, 0, 0, compressedWidth, compressedHeight);
      let base64 = canvas.toDataURL('image/*', 0.8);
      let blob = convertBase64UrlToBlob(base64);
      // 回调函数返回blob的值。也可根据自己的需求返回base64的值
      resolve(blob)
    }
  })
}
复制代码

定义的最大宽度和最大高度均为 500,如果图片的宽高至少有一个超出了 500,都会被 **等比例 **压缩,不用担心变形。可以根据自己项目需要改变maxWidth 和 maxHeight 。

这里直接把压缩的最大高度和最大宽度写死为 500 了,没有在调用时传。因为一个项目压缩的逻辑和大小一般都一致的,没必要在每次调用的时候传。当然如果想写的灵活一点,可以在 compressImage 方法里再把 maxWidth 、 maxHeight 和压缩质量传上。

compressImage 方法返回的是 blob 值,根据服务端接口需要可以改为返回 base64,只需将 resolve(blob) 改为 resolve(base64) 即可。

注意一点,对于有些宽高没到 500,且分辨率很小的图片,压缩之后可能比之前还大。猜测可能是 canvas 生成的图片分辨率要比原来高一些,所以最终的图片比压缩前更大。可以在调用的地方加个判断,如果压缩完的大小比原图小,就上传压缩后的图片;如果如果压缩完的大小比原图大,就上传原图。

二、如何使用

CompressImageUtils 引入到目标文件,然后调用 compressImage 方法,即可在回调里获得压缩后的结果。注意 compressImage 方法返回的是 Promise。
省略其他无关代码,只保留跟压缩图片和上传相关的:

<template>
  <div>
    <van-uploader v-model="fileList" :after-read="afterRead" />
  </div>
</template>

<script>
  import {compressImage} from '../../utils/CompressImageUtils'
  
  export default {
    components: {},
    methods: {
      
     //读取完图片后
      afterRead(file) {
        console.log('afterRead------', file);
        this._compressAndUploadFile(file);
      },

      //压缩图片上传
      _compressAndUploadFile(file) {
        compressImage(file.content).then(result => {
          console.log('压缩后的结果', result); // result即为压缩后的结果
          console.log('压缩前大小', file.file.size);
          console.log('压缩后大小', result.size);
          if (result.size > file.file.size){
            console.log('上传原图');
            //压缩后比原来更大,则将原图上传
            this._uploadFile(file.file, file.file.name);
          } else {
            //压缩后比原来小,上传压缩后的
            console.log('上传压缩图');
            this._uploadFile(result, file.file.name)
          }
        })
      },

      //上传图片
      _uploadFile(file, filename) {
        let params = new FormData();
        params.append("file", file, filename);
        this.$api.uploadImage(params).then(res => {
          console.log('uploadImage', res);
					//上传成功,写自己的逻辑
        }).catch(err => {
          console.log('err', err);
        });
      }, 
    }
  }
</script>
复制代码

在返回结果中加了层判断,压缩后比原来更大,则将原图上传;压缩后比原来小,上传压缩后的。解决压缩后比原图更大的情况。
this.$api.uploadImage(params) 是调用封装的 api 方法,如下:

  //上传图片
 uploadImage(params){
    return axios.post(`${base}/api/v1/file`, params, {
      headers: {'content-type': 'multipart/form-data'}
    })
 },
复制代码

三、使用效果

先上传一个非常大的,尺寸为 6016 × 4016,16.8M 的大图,看输出日志,压缩后大小仅为 260k 左右。此时判断压缩后比压缩前小,上传压缩图到服务器。

image.png

再看个尺寸 300 × 300,12k 的小图,压缩前大小是 11252,压缩后大小是 93656,大了很多。此时判断压缩后比压缩前更大,上传的是原图。

image.png

总结:这个工具类对大图的压缩效果很明显,不管多大的图,压缩之后基本不会超过 300k。但对某些小图可能出现压缩完反而更大的情况。在调用的地方加层压缩后和压缩前大小的比较判断,会完美解决这个问题。
当然也可以在工具类内部判断,但个人觉得跟业务逻辑相关的代码还是不要放在公用的工具类比较好。


Recommend

  • 88
    • 微信 mp.weixin.qq.com 6 years ago
    • Cache

    Android中图片压缩分析(上)

    在 Android 中进行图片压缩是非常常见的开发场景,主要的压缩方法有两种:其一是质量压缩,其二是下采样压缩。前者是在不改变图片尺寸的情况下,改变图片的存储体积,而后者则是降低图像尺寸,达到相同目的。由于本文的篇幅问题,分为上下两篇发布。

  • 63
    • 掘金 juejin.im 5 years ago
    • Cache

    前端图片压缩及上传

    前言 图片的上传一般情况下不需要上传大体积的图片,因为如果是用户头像或者是一些要求清晰度不是太高的场景上传大体积图片会很消耗资源,一个是上传耗时比较长,同时也增加了存储的开销,当展示的时候也会消耗下载的带宽,影响加载效率。要求用户上传的图片之前压...

  • 16
    • quickapp.lovejade.cn 3 years ago
    • Cache

    一键截图、压缩 & 上传至阿里 OSS

    倾城之链 ,旨在云集全球优秀网站,方便你我探索互联网中更广阔的世界 。在倾城,您可以分享(提交)所欢喜的网站;后台将自动为所提交网站首页进行 截图...

  • 8

    App图片压缩裁剪原理和上传方案,以及那些有趣的事儿... | Just My BlogApp图片压缩裁剪原理和上传方案,以及那些有趣的事儿... ...

  • 4

    by zhangxinxu from http://www.zhangxinxu.com/wordpress/?p=6308 本文可全文转载,但需得到原作者书面许可,同时保留原作者和出处,摘要引流则随...

  • 13

    Vue中配置Tinymce富文本编辑器(配置图片上传)https://github.com/surest-sky/example/tree/master/vue/components/Tinymce这里不需要安装,动态加...

  • 3

    还在手动上传网页压缩图片?推荐你一个好用的命令工具!发布于 10 月 9 日咱们前端仔,开发过程中,为了网页的加载性能, 总是免不了需要对使用到的图片进行压缩。

  • 5

    图片选择、预览、压缩、上传一气呵成 – Android开发中文站 现在很多APP中都有上传图片的逻辑,比如头像、审核信息之类的图片,那么就会设计到要选择、压缩等操作,这些如果要纯手写,难度也比较大,最重要的是要适配好主流的机型、版本,所以最后我成了...

  • 6

    springboot项目上传存储图片到七牛云服务器 问题描述: 当图片存在本地时会出现卡顿的现象。比如一篇图文混排的文章,如果图片没有加载完,可能整个文章都显示不出来,因为它们都是用的同一个服务器...

  • 7

    V2EX  ›  OpenAI GPT4 帮我实现 Mac 图片自动压缩上传 COS  

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK