开发一个PicGo图片压缩插件

开源地址

github:https://github.com/liujinpen/picgo-plugin-compress-tinypng.git

npm:https://www.npmjs.com/package/picgo-plugin-tinypng

前言

在写个人博客时,需要上传图片到图床,PicGo是相当不错的工具,但使用过程中发现图片体积较大时,会浪费云存储的空间,因为不需要如此高的清晰度。在之前,较大的图片文件我都选择手动压缩,非常麻烦。

好在PicGo本身支持插件,在搜索之后发现以后已经有支持压缩的插件了:picgo-plugin-compress,但是PicGo-Core从v1.5.0开始,request包底层从Request-Promise-Native 转移到了axios,因此该插件在PicGo客户端2.3.0版本之后使用会报错,且作者长时间并未更新。

在了解了tinify后,决定开发一个适配PicGo的图片压缩插件。

压缩效果

tinify官方:压缩后的图片对视觉的影响几乎不可见,但是在文件大小上有非常大的差别。

这里测试样本较少,但已经可以感受到效果了:

  • 原始图片:1.78MB -> 压缩后:511.9KB

  • 原始图片:27.4KB -> 压缩后:11.5KB

tinify-API使用

tinify为开发者提供了多种api的使用方法,可以注册邮箱获取API key,一个API key每个月有500张免费次数可用,具体API的使用可以参考https://tinify.cn/developers。

PicGo插件开发

官方插件开发文档中较为详细的说明了开发流程,需要有一定的js基础。

1.使用插件模板

使用插件模板首先需要全局安装picgo

npm install picgo -g

初始化项目

picgo init plugin tinypng
注:tinypng为项目名称

创建过程可以根据需要自定义选项,从上到下依次是:

  • 插件名称
  • 插件描述
  • 作者
  • 所开发插件对应的部件(详见文档),压缩图片需要做的是将图片转化为buffer提供给picgo,因此这里选择transformer部件
  • 是否CLI插件(如果需要在图形客户端中使用,选否)
  • 使用TypeScript还是JavaScript(官方推荐TS可以有更好的语法提示,实际上在WebStorm中开发的话,使用JS的体验也非常好)
  • 插件是否要配置快捷键

项目创建完毕后可以使用IDE进行开发。

2.插件配置项

使用tinify的API需要key,因此在插件中配置入口:

const config = ctx => {
  let config = ctx.getConfig('tinypng') || ctx.getConfig('picgo-plugin-tinypng')
  if (!config) {
    config = {}
  }
  ctx.log.info('读取config:', config)
  return [{
    name: 'key', // 配置名
    type: 'input', // 配置类型,input 展示为一个输入框
    default: config.key || null, // 默认值
    required: true, // 是否必填
    message: '填写tinypng的API Key' // 占位符
  }]
}

3.压缩文件

我们在PicGo拖入一张本地图片时,获取到的是本地文件的路径。

压缩的逻辑:

  1. 使用fs-extra库的readFile方法将图片转换为二进制流;
  2. 构造tinify需要的请求(格式化后的API key,文件buffer,其他参数等)
  3. 利用PicGo的request库发送请求
  4. 获取tinify返回的压缩后的图片地址
  5. 利用PicGo的request库下载该图片(获取的是文件buffer)
  6. 构造transformer部件需要的输出格式

至此,插件的工作已经完成了大部分,将我们构造的结果返回,PicGo就可以将压缩后的文件上传至图床。

/**
 * 读取本地图片,上传至tinypng压缩,获取压缩后url,下载图片buffer
 *
 * @param ctx PicGo
 * @param imageUrl 本地图片路径
 * @param key 配置中的api key
 * @returns {Promise<Buffer>}
 */
async function tinypngKeyCompress(ctx, imageUrl, key) {
  return await fs.readFile(imageUrl).then(fileData => {
    // 1.构造请求参数(向tinypng请求)格式参考https://tinify.cn/developers/reference
    const bearer = Base64.stringify(Utf8.parse(`api:${key}`))
    const fetchOptions = {
      method: 'POST',
      url: 'https://api.tinify.com/shrink',
      json: true,
      resolveWithFullResponse: true,
      headers: {
        Host: 'api.tinify.com',
        Authorization: `Basic ${bearer}`
      },
      data: fileData
    }

    // 2.发送压缩请求
    return ctx.request(fetchOptions).then(response => {
      // 3.获取压缩后图片的url
      if (response.status && response.status >= 200 && response.status <= 299) {
        const location = response.headers.location
        ctx.log.info('压缩后的地址:', location)
        
        // 4.从url中获取网络图片
        return utils.fetchImage(ctx, location).then(res => {
          // 5.获取压缩后的图片buffer,构造picGO需要的格式
          return utils.getImageInfo(imageUrl, res.data)
        })
      }
      throw new Error('压缩出错')
    })
  })
}

相关工具类

/**
 * 获取图片信息
 * @param imageUrl
 * @param buffer
 * @returns {{fileName: string, width: number, buffer, extname: string, height: number}}
 */
function getImageInfo(imageUrl, buffer) {
  const {width, height} = imageSize.imageSize(buffer)
  return {
    buffer,
    width: width, //宽度
    height: height, //高度
    fileName: path.basename(imageUrl), // 文件名
    extname: path.extname(imageUrl), //扩展名
  }
}

/**
 * 根据url获取文件信息
 * @param imageUrl
 * @returns {{fileName: string, extname: string}}
 */
function getUrlInfo(imageUrl) {
  return {
    fileName: path.basename(imageUrl),
    extname: path.extname(imageUrl)
  }
}

/**
 * 下载网络图片
 * @param ctx
 * @param url
 * @returns {*}
 */
function fetchImage(ctx, url) {
  return ctx.request({
    method: 'GET',
    url,
    encoding: null,
    resolveWithFullResponse: true,
    responseType: 'arraybuffer'
  })
}

4.完成插件流程

这部分的代码需要按照PicGo插件开发要求进行组织

module.exports = (ctx) => {
  const handle = ctx => {
    // 获取配置的key
    const config = ctx.getConfig('tinypng') || ctx.getConfig('picgo-plugin-tinypng')
    const key = config['key']

    // input是一个路径列表,对每个路径的图片都先进行压缩
    const tasks = ctx.input.map(imageUrl => {
      ctx.log.info('图片地址:' + imageUrl)
      // 调用压缩方法
      return tinypng.tinypngKeyCompress(ctx, imageUrl, key).then(res => {
        return res
      })
    })

    return Promise.all(tasks).then((output) => {
      ctx.output = output
      return ctx
    })
  }

  const config = ctx => {
    let config = ctx.getConfig('tinypng') || ctx.getConfig('picgo-plugin-tinypng')
    if (!config) {
      config = {}
    }
    ctx.log.info('读取config:', config)
    return [{
      name: 'key', // 配置名
      type: 'input', // 配置类型,input 展示为一个输入框
      default: config.key || null, // 默认值
      required: true, // 是否必填
      message: '填写tinypng的API Key' // 占位符
    }]
  }

  const register = () => {
    ctx.helper.transformer.register('tinypng', {handle})
  }
  return {
    transformer: 'tinypng',
    register,
    config
  }
}

本地测试

如果开发模板使用的是JS,在开发完后可以直接在PicGo主界面->插件设置->右上角导入图标->选择源码目录。

是的,选择源码目录,PicGo便能成功加载插件,加载完成后需要重启生效。

导入插件后,需要启用transformer-tinypng选项(显示禁用时代表启用成功):

在这里插入图片描述

配置plugin -picgo-plugin-tinypng选项中可以填入申请的API key以及图床配置名(自定义):

在这里插入图片描述

NPM发布

本文的插件已经发布,在PicGo的插件设置搜索tinypng即可。

npm发布可以参考如何发布自己的npm包

这样别人就可以在PicGo的插件设置中搜索到了。

参考

开发一个 PicGo 插件

PicGo 插件开发入门

PicGo官方插件开发指南

PicGo配置图片压缩(已不可用)

picgo-plugin-compress(已停更插件)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
图片压缩在微信小程序中是一个很常见的需求,下面是一个简单的图片压缩的全过程: 1. 用户选择图片并上传到服务器,服务器返回图片的 URL。 2. 在小程序中,通过 wx.getImageInfo() 方法获取图片信息,包括图片的宽、高等属性。 3. 使用 canvas 绘制图片,并调用 canvas.toDataURL() 方法将图片转换成 base64 编码的字符串。 4. 将 base64 字符串发送到服务器,服务器将其转换成图片并进行压缩处理。 5. 服务器将压缩后的图片返回给小程序,并将其显示在页面上。 下面是一个代码示例: ``` // 选择图片并上传到服务器 wx.chooseImage({ success: function(res) { var tempFilePaths = res.tempFilePaths; wx.uploadFile({ url: 'your server url', filePath: tempFilePaths[0], name: 'file', success: function(res){ var imageUrl = res.data; // 服务器返回的图片 URL // 获取图片信息 wx.getImageInfo({ src: imageUrl, success: function(res){ var canvasWidth = res.width, // 图片宽度 canvasHeight = res.height; // 图片高度 // 绘制图片到 canvas var context = wx.createCanvasContext('canvas'); context.drawImage(imageUrl, 0, 0, canvasWidth, canvasHeight); context.draw(false, function(){ // 将 canvas 图片转换成 base64 编码的字符串 wx.canvasToTempFilePath({ canvasId: 'canvas', success: function(res){ var base64Data = res.tempFilePath.replace(/^data:image\/\w+;base64,/, ''); // 发送 base64 字符串到服务器进行压缩 wx.request({ url: 'your server url', data: { imageData: base64Data }, method: 'POST', success: function(res){ var compressedImageUrl = res.data; // 压缩后的图片 URL // 在页面上显示压缩后的图片 wx.previewImage({ urls: [compressedImageUrl], }); } }); } }); }); } }); } }) } }); ``` 注意,以上代码仅供参考,具体实现方式可能因应用场景不同而有所差异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值