• 微信小程序直传腾讯云COS并对图片持久化文字水印案例


    大家好,我是前端发现者https://blog.csdn.net/Smell_rookie,是一名页面仔工程师,我会不定时在CSDN更新我的博客,有兴趣的可以点个关注来逛逛我的主页。

    写这个需求时网上搜索看到的文章不计其数,很多“缺斤少两”,今天做个总结吧。

    一、前期准备

    1. 到 (COS对象存储控制台)[登录 - 腾讯云] 创建存储桶,得到 Bucket(存储桶名称) 和 Region(地域名称)
    2. 到 (控制台密钥管理)[登录 - 腾讯云] 获取您的项目 SecretId 和 SecretKey

    二、计算签名

    由于签名计算放在前端会暴露 SecretId 和 SecretKey,我们把签名计算过程放在后端实现,前段通过 ajax 向后端获取签名结果,正式部署时请再后端加一层自己网站本身的权限检验。

    三、下载需要的文件

    去到这里下面地址下载文件到项目的utils文件夹下。https://github.com/tencentyun/cos-wx-sdk-v5https://github.com/tencentyun/cos-wx-sdk-v5

    四、实现代码

    在需要执行上传操作的js文件复制如下代码:

    1. const COS = require('./cos-wx-sdk-v5.js')
    2. // 初始化腾讯云存储
    3. const commonCos = new COS({
    4. // ForcePathStyle: true,
    5. // 如果使用了很多存储桶,可以通过打开后缀式,减少配置白名单域名数量,请求时会用地域域名
    6. FileParallelLimit: 40, //同一个实例下上传的文件并发数,默认值3
    7. ChunkParallelLimit: 40, //同一个上传文件的分块并发数,默认值3
    8. //获取签名的回调方法
    9. getAuthorization: (options, callback) => {
    10. // 异步获取临时密钥
    11. http.getRequest('/small/small/getTempScert', {
    12. bucket: options.Bucket,
    13. region: options.Region,
    14. }, res => {
    15. let credentials = res.data.credentials
    16. if (!credentials) return console.error('credentials invalid')
    17. callback({
    18. TmpSecretId: credentials.tmpSecretId,
    19. TmpSecretKey: credentials.tmpSecretKey,
    20. XCosSecurityToken: credentials.sessionToken,
    21. // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
    22. StartTime: res.data.startTime, // 时间戳,单位秒,如:1580000000
    23. ExpiredTime: res.data.expiredTime, // 时间戳,单位秒,如:1580000900
    24. })
    25. })
    26. }
    27. })
    28. // 上传图片 flag:1 需要校验是否需要水印 -1 不校验、不使用水印
    29. const commonUploadImg = async (name, flag = -1, classId = null) => {
    30. return new Promise((resolve) => {
    31. wx.chooseImage({
    32. count: 9,
    33. sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
    34. sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
    35. success: async (res) => {
    36. wx.showLoading({
    37. title: '上传中...',
    38. icon: 'loading',
    39. })
    40. let filenameList = []
    41. let filePathList = []
    42. if (res.tempFiles.length) {
    43. let tempFile = res.tempFiles
    44. let countNum = 0
    45. let waterResult = null
    46. if (flag == 1) {
    47. /**获取水印信息*/
    48. waterResult = await getClassInfoIfWaterMark({
    49. classId: classId,
    50. homeWorkId: name
    51. })
    52. }
    53. for (let temp of tempFile) {
    54. // 这里对图片校验-传入压缩后的图片
    55. const result = true
    56. if (result) {
    57. if (temp.size > 10485760) {
    58. wx.hideLoading()
    59. wx.showToast({
    60. title: `图片最大可以上传${10485760/1024/1024}M`,
    61. icon: 'none',
    62. duration: 1500
    63. })
    64. } else {
    65. const filePath = temp.path
    66. const tempDate = new Date()
    67. const createPath = tempDate.getFullYear() + "" + utils.formatNumber((tempDate.getMonth() + 1)) + "" + utils.formatNumber(tempDate.getDate()) + "/"
    68. const filename = createPath + name + '/' + filePath.substr(filePath.lastIndexOf('/') + 1)
    69. let fileId = filePath.substr(filePath.lastIndexOf('/') + 1)
    70. const wxfs = wx.getFileSystemManager()
    71. let ruleValue = `imageMogr2/format/jpg/interlace/1/rquality/60`
    72. let rule = {
    73. "is_pic_info": 0,
    74. "rules": [{
    75. "fileid": `${fileId}`,
    76. "rule": ruleValue
    77. }]
    78. }
    79. if (flag == 1) {
    80. if (waterResult && waterResult.ifWaterMark) {
    81. let info = `${waterResult.waterFormat}`
    82. let waterInfo = utils.Base64.encode(info)
    83. let fontColor = utils.Base64.encode(waterResult.waterColor || '#09ff00')
    84. let waterPosition = waterResult.waterPosition || 'center'
    85. let waterRangle = waterResult.waterRangle || 0
    86. let water = `watermark/2/text/${waterInfo}/font/c2ltaGVp6buR5L2TLnR0Zg/fill/${fontColor}/fontsize/50/gravity/${waterPosition}/degree/${waterRangle}/dissolve/100`
    87. rule.rules[0].rule = `${ruleValue}|${water}`
    88. }
    89. }
    90. wxfs.readFile({
    91. filePath: filePath,
    92. success(res) {
    93. commonCos.putObject({
    94. Bucket: 'img-work-1304215329',
    95. Region: 'ap-beijing',
    96. Key: filename,
    97. Body: res.data,
    98. Headers: {
    99. // 通过 数据万象的压缩自定义规则 style/uploadStyle
    100. // 'Pic-Operations': `{"is_pic_info": 0, "rules": [{"fileid": "${fileId}","rule": "style/uploadStyle"}]}`,
    101. 'Pic-Operations': `${JSON.stringify(rule)}`
    102. },
    103. }, function (err, data) {
    104. if (data && data.statusCode == 200) {
    105. countNum++
    106. filenameList.push(filename)
    107. filePathList.push(filePath)
    108. if (countNum == tempFile.length) {
    109. wx.hideLoading()
    110. let obj = {
    111. filenameList,
    112. filePathList
    113. }
    114. resolve(obj)
    115. }
    116. }
    117. })
    118. }
    119. })
    120. }
    121. }
    122. }
    123. }
    124. },
    125. fail() {
    126. wx.hideLoading()
    127. }
    128. })
    129. })
    130. }

    持久化处理图片的规则可参考如下:

    数据万象 图片持久化处理-API 文档-文档中心-腾讯云

  • 相关阅读:
    【MindSpore】CPU可以正常运行的,但是GPU下报错
    洗衣液行业调研:预计2028年将达到439亿美元
    Nginx和Tomcat负载均衡实现session共享
    Apache Hudi在信息服务行业构建流批一体的实践
    Spring Batch批量处理数据
    Java多线程
    02【数据库的基本操作】
    微软外服工作札记②——聊聊微软的知识管理服务平台和一些编程风格
    你是否能应对每天数十亿次的IP访问?Top100查找技术解析
    类的成员之一:属性(field)
  • 原文地址:https://blog.csdn.net/Smell_rookie/article/details/127260527