草庐IT

uni-app开发微信小程序,H5 关于压缩上传图片的问题

举个李子ⁱ 2023-04-15 原文

文章目录

前言

一、为什么要压缩图片

二、图片压缩方式

1. 微信小程序​​​​​​​

2. H5

总结


前言

关于微信小程序、H5兼容性问题,今天就压缩以及上传图片做一个可实现方法的简要阐述。


一、为什么要压缩图片​​​​​​​

在使用uni-app开发小程序及H5的具体业务中,我们会遇到需要让用户上传本地图片的场景,随着现在的手机像素越来越高,图片的大小也越来越大,上传原图后一方面是难以上传成功,另一方面是上传成功后在列表中图片太大加载时间过长或者加载失败。若是直接提示用户 “无法上传xxM以上的图片” ,用户体验会不好,于是需要我们对用户上传的图片进行压缩。而不同平台之间压缩图片的方式并不完全兼容,需要提供不同的方法来实现。本文主要记录了在不同平台实现图片压缩上传的其中一种可实现方法。

二、图片压缩方式

uni-app官方提供了关于图片的一系列内置API

首先从选择图片开始

uni.chooseImage(OBJECT)      从本地相册选择图片或使用相机拍照。

// 该方法兼容小程序、H5
uni.chooseImage({
    count:1,
	sizeType: ['compressed'],
	success: res => { // success: 成功则返回图片的本地文件路径列表
	  let size = res.tempFiles[0].size // 选择第一张图片
	  console.log('图片大小', size, `${size/1000}KB`, `${size/1000/1000}MB`)
    }
})

图片选择完毕,下面就是不兼容的地方了 ⬇️

1. 微信小程序​​​​​​​

小程序压缩图片的方式相对比较简单,不过有一定的局限性,仅对 jpg 格式有效。

uni.compressImage(OBJECT)     压缩图片接口,可选压缩质量。

 

// 该方法兼容app和小程序,不兼容h5,且仅对jpg格式有效
uni.compressImage({
    src: src, // 图片路径
	quality: 10, // 图片压缩质量,0~100,默认80,仅对jpg有效
	success: res => {
	    console.log(res.tempFilePath,'压缩后的图片路径')
        // 接下来可以在这里处理图片上传
	}
})

实现图片上传

uni.getFileSystemManager()     获取全局唯一的文件管理器

readFile()     读取文件,可转换编码格式

// 该方法不兼容h5
uni.getFileSystemManager().readFile({
	filePath: path, // 要读取的文件路径
	encoding: 'base64', // 编码格式
	success: file => {
      wx_uploadImage({ // 调用接口实现上传图片,使用其他方式也可以
	    image: `data:image/png;base64,${file.data}`
	  }).then(res => {
	    console.log('上传图片成功', res)
	    this.image = res.storage_path // 赋值或者其他操作
	  })
	}
})

2. H5

H5需要使用另外的方式来压缩图片,这里用到了canvas。

- 分三步 -

1. 使用canvas限制图片大小(压缩图片),并转换为"blob路径";

uni.getImageInfo()     获取图片信息​​​​​​​

uni.getImageInfo({
    src,
	success(res) {
	  console.log('压缩前', res);
	  let canvasWidth = res.width; // 图片原始宽度
	  let canvasHeight = res.height; // 图片原始高度
	  console.log('宽度-',canvasWidth,'高度-',canvasHeight);
	  let img = new Image();
	  img.src = res.path;
	  let canvas = document.createElement('canvas');
	  let ctx = canvas.getContext('2d');
	  // 这里根据要求限制图片宽高
	  if (canvasWidth >= 1000) {
	  	canvas.width = canvasWidth * .1;
	  } else {
	  	canvas.width = canvasWidth;
	  }
	  if (canvasHeight >= 1000) {
	  	canvas.height = canvasHeight * .1;
	  } else {
	  	canvas.height = canvasHeight;
	  }
	  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
	  //toBlob()方法创造Blob对象,用以展示canvas上的图片
	  canvas.toBlob(function(fileSrc) {
	  	let imgSrc = window.URL.createObjectURL(fileSrc);
	  	console.log('压缩后的blob路径', imgSrc);
	  });
    }
});

2. 将 "blob路径" 转换为 "blob文件"(待会转换base64格式图片需要用到 "blob文件" 的格式)

// 传入blob路径,.then()获取blob文件
httpRequest(src) {
    let that = this
	return new Promise((resolve, reject) => {
	  let xhr = new XMLHttpRequest()
	  xhr.open('GET', src, true)
	  xhr.responseType = 'blob'
	  xhr.onload = function (e) {
	      if (this.status == 200) {
	         let myBlob = this.response
	         let files = new window.File(
	            [myBlob],
	            myBlob.type,
	            { type: myBlob.type }
	         ) // myBlob.type 自定义文件名
	            resolve(files)
	         } else {
	            reject(false)
	         }
	      }
	  xhr.send()
    })
},

3. 将 "blob文件" 转换为 base64格式的图片,最后上传图片。

const fileReader = new FileReader()
fileReader.readAsDataURL(file) // 读取blob类型的图像文件(不是blob路径),读取成功触发onload方法,并得到result(base64格式的图片)
fileReader.onload = (event) => {
  console.log(fileReader.result,'fileReader.result - base64格式');
  if (fileReader.result) {
    // 调用wx_uploadImage接口,图片大小必须是1M以下,否则报错
    wx_uploadImage({
      image: fileReader.result
    }).then(res => {
      console.log('上传图片成功', res)
      this.image = res.storage_path
    })
  }
}


总结

总结一下以上逻辑经过封装后的完整代码:

// 使用条件编译区分微信小程序、H5的图片压缩上传方式
// 点击上传图片
chooseImage(){
  uni.chooseImage({
    count:1,
	sizeType: ['compressed'],
	success: res => {
	  let size = res.tempFiles[0].size
	  console.log('图片大小', size, `${size/1000}KB`, `${size/1000/1000}MB`)
	  			
	  let path = this.picture_show = res.tempFilePaths[0] //本地图片路径 - path
	  let file = res.tempFiles[0] //本地图片文件 - file
      let compressPath = ''
				
	  console.log(path,'路径');
	  console.log(file,'图片文件');
				
	  // 先压缩,再转换为base64图片,再上传
				
	  // #ifdef MP-WEIXIN
	  if (size > 1048576) {
		this.mp_compressImage(path)
	  } else {
		this.mp_filetobase64(path)
	  }
	  // #endif
				
	  // #ifdef H5
	  if (size > 1048576) {
	    this.h5_compressImage(path);
	  } else {
		this.h5_filetobase64(file)
	  }
	  // #endif
	}
  })
},

// 微信小程序 - 图片压缩方法
mp_compressImage(src) {
  let _this = this
  // 该方法兼容app和小程序,不兼容h5,且仅对jpg格式有效
  uni.compressImage({
    src: src, // 图片路径
	quality: 10, // 图片压缩质量,0~100,默认80,仅对jpg有效
	success: res => {
	  console.log(res.tempFilePath,'压缩后的图片路径')
      // 接下来可以在这里处理图片上传
      _this.mp_filetobase64(res.tempFilePath)
	}
  })
}

// 微信小程序 - 'blob路径'转base64图片的方法
mp_filetobase64(path) {
  // 该方法不兼容h5
  uni.getFileSystemManager().readFile({
	filePath: path, // 要读取的文件路径
	encoding: 'base64', // 编码格式
	success: file => {
      wx_uploadImage({ // 调用接口实现上传图片,使用其他方式也可以
	    image: `data:image/png;base64,${file.data}`
	  }).then(res => {
	    console.log('上传图片成功', res)
	    this.image = res.storage_path // 赋值或者其他操作
	  })
	}
  })
}

// h5 - 图片压缩方法
h5_compressImage(src) {
  let _this = this;
  uni.getImageInfo({
    src,
	success(res) {
	  console.log('压缩前', res);
	  let canvasWidth = res.width; // 图片原始宽度
	  let canvasHeight = res.height; // 图片原始高度
	  console.log('宽度-',canvasWidth,'高度-',canvasHeight);
	  let img = new Image();
	  img.src = res.path;
	  let canvas = document.createElement('canvas');
	  let ctx = canvas.getContext('2d');
	  // 这里根据要求限制图片宽高
	  if (canvasWidth >= 1000) {
	  	canvas.width = canvasWidth * .1;
	  } else {
	  	canvas.width = canvasWidth;
	  }
	  if (canvasHeight >= 1000) {
	  	canvas.height = canvasHeight * .1;
	  } else {
	  	canvas.height = canvasHeight;
	  }
	  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
	  //toBlob()方法创造Blob对象,用以展示canvas上的图片
	  canvas.toBlob(function(fileSrc) {
	  	let imgSrc = window.URL.createObjectURL(fileSrc);
	  	console.log('压缩后的blob路径', imgSrc);
        // 调用httpRequest方法,把bloburl转换成blob文件
		_this.httpRequest(imgSrc).then(res => {
		    console.log(res,'成功转换为blob文件');
		    _this.h5_filetobase64(res); // 调用方法,把blob文件转换成base64图片
		})
	  });
    }
  });
}

// 传入blob路径,.then()获取blob文件
httpRequest(src) {
    let that = this
	return new Promise((resolve, reject) => {
	  let xhr = new XMLHttpRequest()
	  xhr.open('GET', src, true)
	  xhr.responseType = 'blob'
	  xhr.onload = function (e) {
	      if (this.status == 200) {
	         let myBlob = this.response
	         let files = new window.File(
	            [myBlob],
	            myBlob.type,
	            { type: myBlob.type }
	         ) // myBlob.type 自定义文件名
	            resolve(files)
	         } else {
	            reject(false)
	         }
	      }
	  xhr.send()
    })
},

// h5 - 'blob文件'转base64图片的方法
h5_filetobase64(file) {
  const fileReader = new FileReader()
  fileReader.readAsDataURL(file) // 读取blob类型的图像文件(不是blob路径),读取成功触发onload方法,并得到result(base64格式的图片)
  fileReader.onload = (event) => {
    console.log(fileReader.result,'fileReader.result - base64格式');
    if (fileReader.result) {
      // 调用wx_uploadImage接口,图片大小必须是1M以下,否则报错
      wx_uploadImage({
        image: fileReader.result
      }).then(res => {
        console.log('上传图片成功', res)
        this.image = res.storage_path
      })
    }
  }
}

有关uni-app开发微信小程序,H5 关于压缩上传图片的问题的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  3. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  4. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  5. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  6. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  7. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  8. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  9. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  10. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

随机推荐