Initial commit from cloned source
This commit is contained in:
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.DS_Store
|
||||
yarn-error.log
|
||||
temp.js
|
||||
package-lock.json
|
||||
test.png
|
||||
test2.png
|
||||
12
.npmignore
Normal file
12
.npmignore
Normal file
@@ -0,0 +1,12 @@
|
||||
node_modules/
|
||||
yarn-error.log
|
||||
temp.js
|
||||
package-lock.json
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
.vscode/
|
||||
src/
|
||||
.travis.yml
|
||||
test.png
|
||||
test2.png
|
||||
images/
|
||||
31
.travis.yml
Normal file
31
.travis.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
language: node_js
|
||||
node_js: stable
|
||||
|
||||
# Travis-CI Caching
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
yarn: true
|
||||
|
||||
# S: Build Lifecycle
|
||||
install:
|
||||
- yarn
|
||||
|
||||
stages:
|
||||
- name: deploy
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: deploy
|
||||
script:
|
||||
- npm run build
|
||||
deploy:
|
||||
provider: npm
|
||||
email: ""
|
||||
api_key: "${NPM_TOKEN}"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
branch: master
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
21
License
Normal file
21
License
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 JolyneAnasui
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# picgo-plugin-squoosh
|
||||
|
||||
为[PicGo](https://github.com/Molunerfinn/PicGo)开发的插件
|
||||
|
||||
* 使用[@squoosh/lib](https://github.com/GoogleChromeLabs/squoosh/tree/dev/libsquoosh)压缩图片,所有处理在本地执行,[详见](https://github.com/GoogleChromeLabs/squoosh#privacy)
|
||||
* 使用图片md5进行重命名
|
||||
|
||||

|
||||
|
||||
## 配置
|
||||
|
||||
* 初次使用前请进行配置
|
||||
|
||||

|
||||
|
||||
* `开`表示压缩相应扩展名的图片,反则反之
|
||||
|
||||
* `开`表示使用图片md5进行重命名(与压缩相互独立)
|
||||
|
||||
* 使用squoosh的默认压缩配置,若想定制请修改`index.js`里的`DefaultEncodeOptions`
|
||||
|
||||
BIN
images/1.png
Normal file
BIN
images/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
images/2.png
Normal file
BIN
images/2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
34
package.json
Normal file
34
package.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "picgo-plugin-squoosh",
|
||||
"version": "1.1.0",
|
||||
"description": "使用squoosh压缩图片",
|
||||
"main": "src/index.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"homepage": "https://github.com/JolyneAnasui/picgo-plugin-squoosh",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"patch": "npm version patch && git push origin master && git push origin --tags",
|
||||
"minor": "npm version minor && git push origin master && git push origin --tags",
|
||||
"major": "npm version major && git push origin master && git push origin --tags"
|
||||
},
|
||||
"keywords": [
|
||||
"picgo",
|
||||
"picgo-gui-plugin",
|
||||
"picgo-plugin"
|
||||
],
|
||||
"author": "JolyneAnasui",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"eslint": "^5.0.1",
|
||||
"eslint-config-standard": "^11.0.0",
|
||||
"eslint-plugin-import": "^2.13.0",
|
||||
"eslint-plugin-node": "^6.0.1",
|
||||
"eslint-plugin-promise": "^3.8.0",
|
||||
"eslint-plugin-standard": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@squoosh/lib": "^0.4.0"
|
||||
}
|
||||
}
|
||||
116
src/index.js
Normal file
116
src/index.js
Normal file
@@ -0,0 +1,116 @@
|
||||
const { ImagePool, encoders } = require('@squoosh/lib');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const pluginConfig = ctx => {
|
||||
let userConfig = ctx.getConfig('picgo-plugin-squoosh');
|
||||
if (!userConfig) {
|
||||
userConfig = {};
|
||||
}
|
||||
return [
|
||||
{ name: 'md5-rename', type: 'confirm', alias: 'md5-rename' },
|
||||
{ name: '.jpg', type: 'confirm', alias: 'jpg' },
|
||||
{ name: '.jpeg', type: 'confirm', alias: 'jpeg' },
|
||||
{ name: '.png', type: 'confirm', alias: 'png' },
|
||||
{ name: '.webp', type: 'confirm', alias: 'webp' },
|
||||
{ name: '.avif', type: 'confirm', alias: 'avif' },
|
||||
{ name: '.jxl', type: 'confirm', alias: 'jxl' },
|
||||
{ name: '.wp2', type: 'confirm', alias: 'wp2' }
|
||||
];
|
||||
};
|
||||
|
||||
// 显式定义编码映射
|
||||
const DefaultEncodeOptions = {
|
||||
'.jpg': { webp: {} },
|
||||
'.jpeg': { webp: {} },
|
||||
'.png': { webp: {} },
|
||||
'.webp': { webp: {} },
|
||||
'.avif': { avif: {} },
|
||||
'.jxl': { jxl: {} },
|
||||
'.wp2': { wp2: {} }
|
||||
};
|
||||
|
||||
const handle = async (ctx) => {
|
||||
ctx.log.info('**** squoosh: 转换逻辑启动 ****');
|
||||
let t0 = new Date();
|
||||
|
||||
const userConfig = ctx.getConfig('picgo-plugin-squoosh') || {};
|
||||
let imagePool = new ImagePool();
|
||||
|
||||
const jobs = ctx.output.map(async (outputi) => {
|
||||
try {
|
||||
// 统一小写处理后缀
|
||||
let ext = outputi.extname.toLowerCase();
|
||||
// 特殊处理:有些剪贴板图片可能不带点
|
||||
if (!ext.startsWith('.')) ext = '.' + ext;
|
||||
|
||||
// 1. 判断是否需要压缩/转换
|
||||
if (userConfig[ext] !== false && DefaultEncodeOptions[ext]) {
|
||||
let t = new Date();
|
||||
const encodeConfig = DefaultEncodeOptions[ext];
|
||||
const codecName = Object.keys(encodeConfig)[0]; // 获取目标编码器名,如 'webp'
|
||||
|
||||
let b = outputi.buffer;
|
||||
let ab = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
|
||||
|
||||
let image = imagePool.ingestImage(ab);
|
||||
ctx.log.info(`正在处理: ${outputi.fileName} (源格式: ${ext} -> 目标: ${codecName})`);
|
||||
|
||||
// 2. 核心:执行编码
|
||||
await image.encode(encodeConfig);
|
||||
const encodedData = await image.encodedWith[codecName];
|
||||
|
||||
if (!encodedData) throw new Error(`${codecName} 编码失败`);
|
||||
|
||||
// 3. 替换二进制数据
|
||||
outputi.buffer = Buffer.from(encodedData.binary);
|
||||
|
||||
// 4. 【关键步骤】强制重写文件名和后缀
|
||||
// 只有目标编码器是 webp 且原格式不是 webp 时才修改
|
||||
if (codecName === 'webp' && ext !== '.webp') {
|
||||
const oldName = outputi.fileName;
|
||||
const oldExt = outputi.extname;
|
||||
|
||||
// 修改内部属性,PicGo 上传插件主要依赖这两个属性
|
||||
outputi.extname = '.webp';
|
||||
// 移除旧后缀并追加新后缀
|
||||
if (oldName.toLowerCase().endsWith(oldExt.toLowerCase())) {
|
||||
outputi.fileName = oldName.substring(0, oldName.length - oldExt.length) + '.webp';
|
||||
} else {
|
||||
outputi.fileName = oldName + '.webp';
|
||||
}
|
||||
|
||||
ctx.log.success(`格式转换成功: ${oldName} -> ${outputi.fileName}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. MD5 重命名逻辑 (必须在后缀修改后执行)
|
||||
if (userConfig['md5-rename']) {
|
||||
let hash = crypto.createHash('md5').update(outputi.buffer).digest('hex');
|
||||
outputi.fileName = hash + outputi.extname;
|
||||
ctx.log.info(`MD5 重命名: ${outputi.fileName}`);
|
||||
}
|
||||
|
||||
return outputi;
|
||||
} catch (err) {
|
||||
ctx.log.error(`[Squoosh 失败] ${outputi.fileName}: ${err.stack}`);
|
||||
return outputi;
|
||||
}
|
||||
});
|
||||
|
||||
ctx.output = await Promise.all(jobs);
|
||||
await imagePool.close();
|
||||
ctx.log.info(`**** squoosh 处理结束: ${new Date().getTime() - t0.getTime()}ms ****`);
|
||||
return ctx;
|
||||
};
|
||||
|
||||
module.exports = (ctx) => {
|
||||
const register = () => {
|
||||
ctx.helper.beforeUploadPlugins.register('squoosh', {
|
||||
handle,
|
||||
})
|
||||
}
|
||||
return {
|
||||
register,
|
||||
config: pluginConfig,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user