uploadimage-to-qiniu
VS Code编辑器右键挑选图片上传到七牛云,主动把链接粘贴到当前光标方位,鼠标悬浮在链接上面支持预览图片
啥也不说先看作用!!!
第一步:初始化项目
能够根据官网教程初始化项目,首要重视下图几个文件
第二步:功用开发
- 先看extension.ts 是插件的进口文件,util目录下面几个文件都是基于extension.ts详细功用的办法完成
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import { upImageToQiniu } from './util/upload';
import { getHoverHttpLink, translateImageUrlToBase64 } from './util/handleHover';
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let texteditor = vscode.commands.registerTextEditorCommand(
'extension.choosedImage',
async (textEditor, edit, args) => {
console.log('挑选图片');
const qiniuConfig = vscode.workspace.getConfiguration('upload_qiniu_config');
const uri = await vscode.window.showOpenDialog({
canSelectFolders: false,
canSelectMany: false,
filters: {
images: ['png', 'jpg', 'gif', 'jpeg', 'svg'],
},
});
if (!uri) {
return;
}
const upConfig = {
accessKey: qiniuConfig.accessKey,
secretKey: qiniuConfig.secretKey,
domain: qiniuConfig.domain,
gzip: qiniuConfig.gzip,
scope: qiniuConfig.scope,
directory: qiniuConfig.directory,
imageWidth: qiniuConfig.imageWidth,
formatWebp: qiniuConfig.formatWebp
};
const loaclFile = uri[0].fsPath;
upImageToQiniu(
loaclFile,
(res: string) => {
let url = res;
// 将图片链接写入编辑器
if(upConfig.imageWidth !== ''){
url = `${url}?imageView2/2/w/${upConfig.imageWidth}`;
}
if(upConfig.formatWebp){
url = `${url}/format/webp`;
}
console.log('图片上传成功', url);
addImageUrlToEditor(url);
},
upConfig
);
}
);
// 鼠标悬浮预览图片
vscode.languages.registerHoverProvider('*', {
async provideHover(document, position) {
try {
const { character } = position;
// 当前行的文本内容
const currentLineText = document.lineAt(position).text;
// 匹配当前行内
const httpLink = getHoverHttpLink(currentLineText, character);
var strToBase64 = await translateImageUrlToBase64(httpLink);
const markString = strToBase64 ? new vscode.MarkdownString(`![](${strToBase64})`, true) : '';
return {
contents: [markString],
};
} catch (err) {
console.log('error', err);
}
},
});
context.subscriptions.push(texteditor);
}
// 将图片链接写入编辑器
function addImageUrlToEditor(url: string) {
let editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
// 替换内容
const selection = editor.selection;
editor.edit((editBuilder) => {
editBuilder.replace(selection, url);
});
}
// this method is called when your extension is deactivated
export function deactivate() {}
- util/upload.ts 完成上传到七牛云的办法
const path = require('path');
const fs = require('fs');
const qiniu = require('qiniu');
const imagemin = require('imagemin');
const imageminPngquant = require('imagemin-pngquant');
const imageminJpegtran = require('imagemin-jpegtran');
import * as vscode from 'vscode';
import { getBufferFromFile, bufferToStream } from './base';
// 获取七牛token
const getToken = (accessKey: string, secretKey: string, scope: string) => {
const options = {
scope,
};
const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
const putPolicy = new qiniu.rs.PutPolicy(options);
const uploadToken = putPolicy.uploadToken(mac);
return uploadToken;
};
// 图片紧缩
const imageGzip = async (loaclFile: string): Promise<any> => {
const bufferFile = await getBufferFromFile(loaclFile);
let res;
try {
res = await imagemin.buffer(bufferFile, {
plugins: [
imageminJpegtran(),
imageminPngquant({
quality: [0.6, 0.8],
}),
],
});
console.log('图片紧缩成功', res);
} catch (err) {
vscode.window.showInformationMessage('图片紧缩失利');
res = null;
}
return res;
};
// 七牛上传装备
export interface QiNiuUpConfig {
domain: string // 上传后域名
accessKey: string // 七牛参数
secretKey: string // 七牛参数
scope: string // 七牛上传空间
gzip: boolean // 是否需求紧缩
directory: string // 指定目录
imageWidth: string // 图片展示宽度
formatWebp: boolean // 是否主动转成webp格局
}
// 上传图片到七牛云
export const upImageToQiniu = async (
loaclFile: string,
cb: { (res: any): void; (arg0: any): void },
upConfig: QiNiuUpConfig
) => {
// 将图片途径一致为 xx/xxx
const filePathArr = loaclFile.split(path.sep);
loaclFile = path.posix.join(...filePathArr);
const config = new qiniu.conf.Config();
const formUploader = new qiniu.form_up.FormUploader(config);
const putExtra = new qiniu.form_up.PutExtra();
const token = getToken(upConfig.accessKey, upConfig.secretKey, upConfig.scope);
let gzipImage;
if (upConfig.gzip) {
console.log('现已开启紧缩');
gzipImage = await imageGzip(loaclFile);
}
const file = filePathArr.pop();
const fileName = file?.split('.')[0];
const fileType = file?.split('.')[1];
// 文件目录+文件名称
const keyToOverwrite = `${upConfig.directory}/${fileName}-${new Date().getTime()}.${fileType}`;
// 上传调用办法
const uploadFnName = gzipImage ? 'putStream' : 'putFile';
// 上传内容
const uploadItem = gzipImage ? bufferToStream(gzipImage) : path.normalize(loaclFile);
// 七牛上传
formUploader[uploadFnName](
token,
keyToOverwrite,
uploadItem,
putExtra,
function (respErr: any, respBody: any, respInfo: any) {
if (respErr) {
throw respErr;
}
if (respInfo.statusCode === 200) {
const url = `${upConfig.domain}/${respBody.key}`;
cb(url);
} else {
vscode.window.showInformationMessage(`上传失利: ${respInfo.statusCode}`);
}
}
);
};
- util/base.ts
const fs = require('fs');
const duplex = require('stream').Duplex;
// 获取buffer
export const getBufferFromFile = (filePath: string): Promise<Buffer> => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, function (err: any, res: any) {
if (!err) {
resolve(res);
}
});
});
};
// buffer 转 stream
export const bufferToStream = (buffer: Buffer) => {
let stream = new duplex();
stream.push(buffer);
stream.push(null);
return stream;
};
- util/handleHover.ts 完成链接主动粘贴到光标方位和鼠标悬浮链接上面预览图片
import * as https from 'https';
import * as http from 'http';
// 将链接左右两边的引号删掉
const filterHttpLink = (link: string): string => {
if (link) {
link = link.substr(0, link.length - 1);
link = link.substr(1);
}
return link;
};
// 获取http链接 在字符串中的方位
const getHttpLinkPosition = (content: string): Array<any> => {
const regx = /["|'][http(s)://](.*?)["|']/g;
// @ts-ignore
const matchArr = [...content.matchAll(regx)];
const arr: any[] = [];
matchArr.forEach((item: any) => {
const url = filterHttpLink(item[0]);
arr.push({
start: item.index - 1,
end: item.index - 1 + url.length,
value: url,
length: url.length
});
});
return arr;
};
// 获取hover的 http链接
export const getHoverHttpLink = (content: string, position: number): string => {
let link = '';
const httpPositions = getHttpLinkPosition(content);
if (httpPositions.length) {
httpPositions.forEach((item) => {
if (item.start <= position && item.end >= position) {
link = item.value;
}
});
}
return link;
};
// 图片增加裁剪参数
export const addImageCropParam = (
url: string,
width?: number,
height?: number,
type?: number
): string => {
// 假如url中现已带有裁剪参数,先去掉之前的参数
const [path] = url.split('?imageView2');
url = path;
let cropUrl = type ? `?imageView2/${type}` : '?imageView2/2';
if (!!width) {
cropUrl += `/w/${width}`;
}
if (!!height) {
cropUrl += `/h/${height}`;
}
if (!!width || !!height) {
url += cropUrl;
}
return url;
};
// 将图片链接转为base64
export const translateImageUrlToBase64 = (url: string): Promise<string> => {
return new Promise((resolve, reject) => {
let resUrl = '';
// 链接是否为https
const isHttps = url.includes('https');
if (!url) {
resolve(resUrl);
} else {
url = addImageCropParam(url, 100)
;(isHttps ? https : http).get(url, {}, function (res: http.IncomingMessage) {
const contentType = res.headers['content-type'];
// 恳求为图片
if (contentType && contentType.includes('image')) {
var chunks: Array<any> = []; //用于保存网络恳求不断加载传输的缓冲数据
var size = 0; //保存缓冲数据的总长度
res.on('data', function (chunk: any) {
chunks.push(chunk);
//累加缓冲数据的长度
size += chunk.length;
});
res.on('end', function (err: any) {
//Buffer.concat将chunks数组中的缓冲数据拼接起来,回来一个新的Buffer目标赋值给data
var data = Buffer.concat(chunks, size);
//将Buffer目标转换为字符串并以base64编码格局显示
const base64Img = data.toString('base64');
resolve(`data:image/png;base64,${base64Img}`);
});
} else {
resolve(resUrl);
}
});
}
});
};
第三步:插件装备
package.json 包含插件的装备信息(插件指令、快捷键、菜单均在此装备)
- menus
- editor/context 编辑器上下文菜单
- when 操控菜单何时呈现
- command 界说菜单被点击后要履行什么操作
- group 界说菜单分组
- editor/context 编辑器上下文菜单
- command 指令装备
- configuration 插件装备
"contributes": {
"menus": {
"editor/context": [
{
"when": "editorFocus",
"command": "extension.choosedImage",
"group": "navigation"
}
]
},
"commands": [
{
"command": "extension.choosedImage",
"title": "挑选图片"
}
],
"configuration": [
{
"title": "上传七牛插件装备项",
"properties": {
"upload_qiniu_config.domain": {
"type": "string",
"default": "",
"description": "设置上传域名"
},
"upload_qiniu_config.accessKey": {
"type": "string",
"default": "",
"description": "设置七牛上传accessKey"
},
"upload_qiniu_config.secretKey": {
"type": "string",
"default": "",
"description": "设置七牛上传secretKey"
},
"upload_qiniu_config.scope": {
"type": "string",
"default": "",
"description": "设置七牛上传上传空间"
},
"upload_qiniu_config.gzip": {
"type": "boolean",
"default": "true",
"description": "是否启用图片紧缩"
},
"upload_qiniu_config.directory": {
"type": "string",
"default": "",
"description": "设置七牛上传指定目录"
},
"upload_qiniu_config.imageWidth": {
"type": "string",
"default": "",
"description": "设置图片展示宽度"
},
"upload_qiniu_config.formatWebp": {
"type": "boolean",
"default": "",
"description": "是否主动转成webp格局"
}
}
}
]
},
第四步:本地调试
- 装置vsce打包东西
npm install -g vsce
- 履行打包指令
vsce package
打包完成后会在根目录出产.vsix文件,点击右键挑选“装置扩展VSIX”
- 运转调试
默许情况下,工程现已帮咱们装备好了调试相关参数(有兴趣的能够查看.vscode/launch.json
文件的写法),切换到vscode运转和调试面板,然后点击Run Extension,默许会打开一个新窗口,然后咱们就能够在新窗口去测验和验证,调试操控台也能够看到console.log的输出成果。
本地验证没问题的话,那就能够预备发布了~~
第五步:发布
-
注册账号login.live.com/
-
拜访aka.ms/SignupAzure…,假如你从来没有使用过Azure,那么会看到如下提示:
点击继续,默许会创立一个以邮箱前缀为名的安排。
- 默许进入安排的主页后,点击右上角的
Security
:
点击创立新的个人拜访令牌,这儿特别要注意Organization
要挑选all accessible organizations
,Scopes
要挑选Full access
,不然后面发布会失利。
创立令牌成功后你需求本地记下来,因为网站是不会帮你保存的。
- 获得个人拜访令牌后,使用
vsce
以下指令创立新的发布者:
vsce create-publisher your-publisher-name
创立成功后会默许登录这个账号,接下来你能够直接发布了,当然,假如你是在其它当地创立的,能够试用vsce login your-publisher-name
来登录。
- 履行发布指令
npm run pubilsh
发布成功后,能够拜访marketplace.visualstudio.com… 查看
在VSCode中也能够查找进行装置
- 增量发布
版本号:major.minor.patch
假如想让发布之后版本号的patch自增,例如:1.0.2
-> 1.0.3
,能够履行指令
vsce publish patch
以此类推…
郑重声明: 文章有参阅自 从零开发Vscode上传图片插件,如有侵权,请联系删去!