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