@hzab/utils 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.md CHANGED
@@ -1,3 +1,11 @@
1
+ # @hzab/utils@1.0.15
2
+
3
+ feat: 二维码,创建路径,区分前缀
4
+
5
+ # @hzab/utils@1.0.14
6
+
7
+ feat: 添加压缩图片函数
8
+
1
9
  # @hzab/utils@1.0.13
2
10
 
3
11
  feat: upload axios ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzab/utils",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "utils",
5
5
  "main": "src",
6
6
  "scripts": {
package/src/img-utils.ts CHANGED
@@ -1,340 +1,456 @@
1
- export class IMAGE_TYPES {
2
- static JPEG = "image/jpeg";
3
- static PNG = "image/png";
4
- }
5
-
6
- /**
7
- * 检测空图片
8
- * @param img
9
- * @returns
10
- */
11
- export function checkEmptyImg(img: HTMLImageElement) {
12
- // 创建一个 Canvas 元素
13
- const canvas = document.createElement("canvas");
14
- const ctx = canvas.getContext("2d");
15
- if (!ctx) {
16
- return;
17
- }
18
-
19
- // 设置 Canvas 的宽度和高度与图片一致
20
- canvas.width = img.width;
21
- canvas.height = img.height;
22
- // 将图片绘制到Canvas上
23
- ctx.drawImage(img, 0, 0);
24
- // 获取Canvas中的像素数据
25
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
26
- const data = imageData.data;
27
-
28
- // 判断从左上角到右下角的像素是否都是黑色
29
- let topLeftToBottomRight = true;
30
-
31
- const iUp = 0;
32
- const redUp = data[iUp];
33
- const greenUp = data[iUp + 1];
34
- const blueUp = data[iUp + 2];
35
- const alphaUp = data[iUp + 3];
36
- for (let i = 0; i < data.length; i += 4) {
37
- const red = data[i];
38
- const green = data[i + 1];
39
- const blue = data[i + 2];
40
- const alpha = data[i + 3];
41
-
42
- if (red !== redUp || green !== greenUp || blue !== blueUp || alpha !== alphaUp) {
43
- topLeftToBottomRight = false;
44
- break;
45
- }
46
- }
47
-
48
- // 判断从右上角到左下角的像素是否都是黑色
49
- let topRightToBottomLeft = true;
50
- const jDown = data.length - 4;
51
- const redDown = data[jDown];
52
- const greenDown = data[jDown + 1];
53
- const blueDown = data[jDown + 2];
54
- const alphaDown = data[jDown + 3];
55
-
56
- for (let j = jDown; j >= 0; j -= 4) {
57
- const red = data[j];
58
- const green = data[j + 1];
59
- const blue = data[j + 2];
60
- const alpha = data[j + 3];
61
-
62
- if (red !== redDown || green !== greenDown || blue !== blueDown || alpha !== alphaDown) {
63
- topRightToBottomLeft = false;
64
- break;
65
- }
66
- }
67
-
68
- // 打印结果
69
- if (topLeftToBottomRight && topRightToBottomLeft) {
70
- return false;
71
- } else {
72
- return true;
73
- }
74
- }
75
-
76
- /**
77
- * 获取dom元素宽高
78
- * @param d dom元素
79
- * @returns {{width: number, height: number}}
80
- */
81
- export function getDomWH(d: HTMLElement | HTMLImageElement | HTMLCanvasElement) {
82
- if (d instanceof Image || d instanceof HTMLCanvasElement) {
83
- return {
84
- width: d.width || d.offsetWidth,
85
- height: d.width || d.offsetHeight,
86
- };
87
- }
88
- return {
89
- width: d.offsetWidth,
90
- height: d.offsetHeight,
91
- };
92
- }
93
-
94
- /**
95
- * 设置dom元素宽高
96
- * @param d dom元素
97
- * @param w 宽
98
- * @param h 高
99
- */
100
- export function setDomWH(dom: HTMLElement, w: number, h: number) {
101
- dom.setAttribute("width", `${w}`);
102
- dom.setAttribute("height", `${h}`);
103
- }
104
-
105
- /**
106
- * 获取当前 canvas 图片 Blob 对象
107
- * @param canvas
108
- * @returns {Promise<Blob>}
109
- */
110
- export function getCanvasPic(canvas: HTMLCanvasElement): Blob {
111
- var gl = canvas.getContext("2d", { preserveDrawingBuffer: true });
112
-
113
- return dataURItoBlob(canvas.toDataURL(IMAGE_TYPES.PNG, 1));
114
- }
115
-
116
- /**
117
- * base64 字符串转 blob
118
- * @param base64
119
- * @returns
120
- */
121
- export function dataURItoBlob(base64: string): Blob {
122
- let arr = base64.split(",");
123
- let mime = arr[0]?.match(/:(.*?);/)?.[1];
124
- let bstr = atob(arr[1]);
125
- let n = bstr.length;
126
- let u8arr = new Uint8Array(n);
127
- while (n--) {
128
- u8arr[n] = bstr.charCodeAt(n);
129
- }
130
- return new Blob([u8arr], { type: mime });
131
- }
132
-
133
- /**
134
- * 获取图片元素
135
- * @param imgSrc
136
- * @returns
137
- */
138
- export function getImgEle(imgSrc: string): Promise<HTMLImageElement> {
139
- return new Promise((resolve) => {
140
- const img = new Image();
141
- img.onload = function () {
142
- resolve(img);
143
- };
144
- img.src = imgSrc;
145
- });
146
- }
147
-
148
- /**
149
- * 获取图片 Base64 字符串
150
- * @param imgSrc
151
- * @returns
152
- */
153
- export function getImgBase64(imgSrc: string): Promise<string> {
154
- return getImgEle(imgSrc).then((img) => {
155
- const canvas = document.createElement("canvas");
156
- let { width, height } = getDomWH(img);
157
- setDomWH(canvas, width, height);
158
- const ctx = canvas.getContext("2d");
159
- ctx && ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
160
- return canvas.toDataURL(IMAGE_TYPES.PNG, 1);
161
- });
162
- }
163
-
164
- /**
165
- * 通过图片地址获取对应 canvas
166
- * @param imgSrc
167
- * @returns
168
- */
169
- export function getCanvas(imgSrc: string): Promise<HTMLCanvasElement> {
170
- return getImgEle(imgSrc).then((img) => {
171
- const canvas = document.createElement("canvas");
172
- let { width, height } = getDomWH(img);
173
- setDomWH(canvas, width, height);
174
- const ctx = canvas.getContext("2d");
175
- ctx && ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
176
- return canvas;
177
- });
178
- }
179
-
180
- /**
181
- * 通过图片地址获取对应 canvas
182
- * @param img
183
- * @returns
184
- */
185
- export function getCanvasByImg(img: HTMLImageElement): HTMLCanvasElement {
186
- const canvas = document.createElement("canvas");
187
- let { width, height } = getDomWH(img);
188
- setDomWH(canvas, width, height);
189
- const ctx = canvas.getContext("2d");
190
- ctx && ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
191
- return canvas;
192
- }
193
-
194
- /**
195
- * 截取图片
196
- * @param img
197
- * @param opt
198
- * @param opt.startX
199
- * @param opt.startY
200
- * @param opt.width
201
- * @param opt.height
202
- * @returns Promise<string>
203
- */
204
- export function cropImage(
205
- img: HTMLImageElement | HTMLCanvasElement,
206
- opt: { startX: number; startY: number; width: number; height: number },
207
- ) {
208
- return cropImageToCanvas(img, opt).toDataURL(IMAGE_TYPES.PNG, 1);
209
- }
210
-
211
- /**
212
- * 截取图片
213
- * @param img
214
- * @param opt
215
- * @param opt.startX
216
- * @param opt.startY
217
- * @param opt.width
218
- * @param opt.height
219
- * @returns Promise<HTMLCanvasElement>
220
- */
221
- export function cropImageToCanvas(
222
- img: HTMLImageElement | HTMLCanvasElement,
223
- opt: { startX: number; startY: number; width: number; height: number },
224
- ) {
225
- const { startX, startY, width, height } = opt;
226
- const canvas = document.createElement("canvas");
227
- const ctx = canvas.getContext("2d");
228
- // 设置 canvas 的宽度和高度为裁剪后的尺寸
229
- canvas.width = width; // 裁剪后的宽度
230
- canvas.height = height; // 裁剪后的高度
231
- // 在 canvas 上绘制裁剪后的图像
232
- ctx?.drawImage(img, startX, startY, width, height, 0, 0, width, height);
233
- // 可以将裁剪后的图像数据获取出来
234
- return canvas;
235
- }
236
-
237
- /**
238
- * 绘制图片
239
- * @param img
240
- * @param opt
241
- * @param opt.startX
242
- * @param opt.startY
243
- * @param opt.width
244
- * @param opt.height
245
- * @returns Promise<string>
246
- */
247
- export function imgToCanvas(img: HTMLImageElement) {
248
- const canvas = document.createElement("canvas");
249
- const ctx = canvas.getContext("2d");
250
- canvas.width = img.width;
251
- canvas.height = img.height;
252
- ctx?.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
253
- return canvas;
254
- }
255
-
256
- /**
257
- * 缩放图片
258
- * @param img
259
- * @param opt
260
- * @returns base64
261
- */
262
- export function scaleImage(img: HTMLImageElement | HTMLCanvasElement, opt = { scaleFactor: 1 }) {
263
- return scaleImageToCanvas(img, opt).toDataURL(IMAGE_TYPES.PNG, 1);
264
- }
265
-
266
- /**
267
- * 缩放图片,返回 canvas
268
- * @param img
269
- * @param opt
270
- * @returns canvas
271
- */
272
- export function scaleImageToCanvas(img: HTMLImageElement | HTMLCanvasElement, opt = { scaleFactor: 1 }) {
273
- const { scaleFactor = 1 } = opt;
274
- const canvas = document.createElement("canvas");
275
- const ctx = canvas.getContext("2d");
276
- canvas.width = img.width * scaleFactor;
277
- canvas.height = img.height * scaleFactor;
278
- ctx?.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
279
- return canvas;
280
- }
281
-
282
- /**
283
- * 图片转为 base64
284
- * @param img
285
- * @returns
286
- */
287
- export async function imgToBase64(img: string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement) {
288
- if (!img || img instanceof Blob) {
289
- return img;
290
- }
291
- let _img = img;
292
- if (img instanceof Image) {
293
- _img = img.src;
294
- } else if (img instanceof HTMLVideoElement) {
295
- // 从视频中获取图片
296
- const canvas = document.createElement("canvas");
297
- let { width, height } = getDomWH(img);
298
- setDomWH(canvas, width, height);
299
- const ctx = canvas.getContext("2d");
300
- ctx && ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
301
- _img = canvas.toDataURL(IMAGE_TYPES.PNG, 1);
302
- } else if (img instanceof HTMLCanvasElement) {
303
- _img = img.toDataURL(IMAGE_TYPES.PNG, 1);
304
- } else if (typeof _img === "string" && !_img.startsWith("data:image/")) {
305
- // 加载图片,并获取图片 base64
306
- _img = await getImgBase64(_img);
307
- }
308
- return _img;
309
- }
310
-
311
- /**
312
- * 图片转为 Blob
313
- * @param img
314
- * @returns
315
- */
316
- export async function imgToBlob(img: string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement): Promise<Blob> {
317
- if (!img) {
318
- throw new Error("请传入图片数据");
319
- }
320
- if (img instanceof Blob) {
321
- return Promise.resolve(img);
322
- }
323
- const _img = await imgToBase64(img);
324
- if (typeof _img !== "string") {
325
- throw new Error("传入的图片数据不正确");
326
- }
327
- return dataURItoBlob(_img);
328
- }
329
-
330
- /**
331
- * 获取图片的 base64、blob 格式
332
- * @param img
333
- */
334
- export async function getAllTypeImg(img: string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement) {
335
- const base64 = await imgToBase64(img);
336
- return {
337
- base64,
338
- blob: typeof base64 === "string" && dataURItoBlob(base64),
339
- };
340
- }
1
+ export class IMAGE_TYPES {
2
+ static JPEG = "image/jpeg";
3
+ static PNG = "image/png";
4
+ }
5
+
6
+ /**
7
+ * 检测空图片
8
+ * @param img
9
+ * @returns
10
+ */
11
+ export function checkEmptyImg(img: HTMLImageElement) {
12
+ // 创建一个 Canvas 元素
13
+ const canvas = document.createElement("canvas");
14
+ const ctx = canvas.getContext("2d");
15
+ if (!ctx) {
16
+ return;
17
+ }
18
+
19
+ // 设置 Canvas 的宽度和高度与图片一致
20
+ canvas.width = img.width;
21
+ canvas.height = img.height;
22
+ // 将图片绘制到Canvas上
23
+ ctx.drawImage(img, 0, 0);
24
+ // 获取Canvas中的像素数据
25
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
26
+ const data = imageData.data;
27
+
28
+ // 判断从左上角到右下角的像素是否都是黑色
29
+ let topLeftToBottomRight = true;
30
+
31
+ const iUp = 0;
32
+ const redUp = data[iUp];
33
+ const greenUp = data[iUp + 1];
34
+ const blueUp = data[iUp + 2];
35
+ const alphaUp = data[iUp + 3];
36
+ for (let i = 0; i < data.length; i += 4) {
37
+ const red = data[i];
38
+ const green = data[i + 1];
39
+ const blue = data[i + 2];
40
+ const alpha = data[i + 3];
41
+
42
+ if (red !== redUp || green !== greenUp || blue !== blueUp || alpha !== alphaUp) {
43
+ topLeftToBottomRight = false;
44
+ break;
45
+ }
46
+ }
47
+
48
+ // 判断从右上角到左下角的像素是否都是黑色
49
+ let topRightToBottomLeft = true;
50
+ const jDown = data.length - 4;
51
+ const redDown = data[jDown];
52
+ const greenDown = data[jDown + 1];
53
+ const blueDown = data[jDown + 2];
54
+ const alphaDown = data[jDown + 3];
55
+
56
+ for (let j = jDown; j >= 0; j -= 4) {
57
+ const red = data[j];
58
+ const green = data[j + 1];
59
+ const blue = data[j + 2];
60
+ const alpha = data[j + 3];
61
+
62
+ if (red !== redDown || green !== greenDown || blue !== blueDown || alpha !== alphaDown) {
63
+ topRightToBottomLeft = false;
64
+ break;
65
+ }
66
+ }
67
+
68
+ // 打印结果
69
+ if (topLeftToBottomRight && topRightToBottomLeft) {
70
+ return false;
71
+ } else {
72
+ return true;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * 获取dom元素宽高
78
+ * @param d dom元素
79
+ * @returns {{width: number, height: number}}
80
+ */
81
+ export function getDomWH(d: HTMLElement | HTMLImageElement | HTMLCanvasElement) {
82
+ if (d instanceof Image || d instanceof HTMLCanvasElement) {
83
+ return {
84
+ width: d.width || d.offsetWidth,
85
+ height: d.width || d.offsetHeight,
86
+ };
87
+ }
88
+ return {
89
+ width: d.offsetWidth,
90
+ height: d.offsetHeight,
91
+ };
92
+ }
93
+
94
+ /**
95
+ * 设置dom元素宽高
96
+ * @param d dom元素
97
+ * @param w 宽
98
+ * @param h 高
99
+ */
100
+ export function setDomWH(dom: HTMLElement, w: number, h: number) {
101
+ dom.setAttribute("width", `${w}`);
102
+ dom.setAttribute("height", `${h}`);
103
+ }
104
+
105
+ /**
106
+ * 获取当前 canvas 图片 Blob 对象
107
+ * @param canvas
108
+ * @returns {Promise<Blob>}
109
+ */
110
+ export function getCanvasPic(canvas: HTMLCanvasElement): Blob {
111
+ var gl = canvas.getContext("2d", { preserveDrawingBuffer: true });
112
+
113
+ return dataURItoBlob(canvas.toDataURL(IMAGE_TYPES.PNG, 1));
114
+ }
115
+
116
+ /**
117
+ * base64 字符串转 blob
118
+ * @param base64
119
+ * @returns
120
+ */
121
+ export function dataURItoBlob(base64: string): Blob {
122
+ let arr = base64.split(",");
123
+ let mime = arr[0]?.match(/:(.*?);/)?.[1];
124
+ let bstr = atob(arr[1]);
125
+ let n = bstr.length;
126
+ let u8arr = new Uint8Array(n);
127
+ while (n--) {
128
+ u8arr[n] = bstr.charCodeAt(n);
129
+ }
130
+ return new Blob([u8arr], { type: mime });
131
+ }
132
+
133
+ /**
134
+ * 获取图片元素
135
+ * @param imgSrc
136
+ * @returns
137
+ */
138
+ export function getImgEle(imgSrc: string): Promise<HTMLImageElement> {
139
+ return new Promise((resolve) => {
140
+ const img = new Image();
141
+ img.onload = function () {
142
+ resolve(img);
143
+ };
144
+ img.src = imgSrc;
145
+ });
146
+ }
147
+
148
+ /**
149
+ * 获取图片 Base64 字符串
150
+ * @param imgSrc
151
+ * @returns
152
+ */
153
+ export function getImgBase64(imgSrc: string): Promise<string> {
154
+ return getImgEle(imgSrc).then((img) => {
155
+ const canvas = document.createElement("canvas");
156
+ let { width, height } = getDomWH(img);
157
+ setDomWH(canvas, width, height);
158
+ const ctx = canvas.getContext("2d");
159
+ ctx && ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
160
+ return canvas.toDataURL(IMAGE_TYPES.PNG, 1);
161
+ });
162
+ }
163
+
164
+ /**
165
+ * 通过图片地址获取对应 canvas
166
+ * @param imgSrc
167
+ * @returns
168
+ */
169
+ export function getCanvas(imgSrc: string): Promise<HTMLCanvasElement> {
170
+ return getImgEle(imgSrc).then((img) => {
171
+ const canvas = document.createElement("canvas");
172
+ let { width, height } = getDomWH(img);
173
+ setDomWH(canvas, width, height);
174
+ const ctx = canvas.getContext("2d");
175
+ ctx && ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
176
+ return canvas;
177
+ });
178
+ }
179
+
180
+ /**
181
+ * 通过图片地址获取对应 canvas
182
+ * @param img
183
+ * @returns
184
+ */
185
+ export function getCanvasByImg(img: HTMLImageElement): HTMLCanvasElement {
186
+ const canvas = document.createElement("canvas");
187
+ let { width, height } = getDomWH(img);
188
+ setDomWH(canvas, width, height);
189
+ const ctx = canvas.getContext("2d");
190
+ ctx && ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
191
+ return canvas;
192
+ }
193
+
194
+ /**
195
+ * 截取图片
196
+ * @param img
197
+ * @param opt
198
+ * @param opt.startX
199
+ * @param opt.startY
200
+ * @param opt.width
201
+ * @param opt.height
202
+ * @returns Promise<string>
203
+ */
204
+ export function cropImage(
205
+ img: HTMLImageElement | HTMLCanvasElement,
206
+ opt: { startX: number; startY: number; width: number; height: number },
207
+ ) {
208
+ return cropImageToCanvas(img, opt).toDataURL(IMAGE_TYPES.PNG, 1);
209
+ }
210
+
211
+ /**
212
+ * 截取图片
213
+ * @param img
214
+ * @param opt
215
+ * @param opt.startX
216
+ * @param opt.startY
217
+ * @param opt.width
218
+ * @param opt.height
219
+ * @returns Promise<HTMLCanvasElement>
220
+ */
221
+ export function cropImageToCanvas(
222
+ img: HTMLImageElement | HTMLCanvasElement,
223
+ opt: { startX: number; startY: number; width: number; height: number },
224
+ ) {
225
+ const { startX, startY, width, height } = opt;
226
+ const canvas = document.createElement("canvas");
227
+ const ctx = canvas.getContext("2d");
228
+ // 设置 canvas 的宽度和高度为裁剪后的尺寸
229
+ canvas.width = width; // 裁剪后的宽度
230
+ canvas.height = height; // 裁剪后的高度
231
+ // 在 canvas 上绘制裁剪后的图像
232
+ ctx?.drawImage(img, startX, startY, width, height, 0, 0, width, height);
233
+ // 可以将裁剪后的图像数据获取出来
234
+ return canvas;
235
+ }
236
+
237
+ /**
238
+ * 绘制图片
239
+ * @param img
240
+ * @param opt
241
+ * @param opt.startX
242
+ * @param opt.startY
243
+ * @param opt.width
244
+ * @param opt.height
245
+ * @returns Promise<string>
246
+ */
247
+ export function imgToCanvas(img: HTMLImageElement) {
248
+ const canvas = document.createElement("canvas");
249
+ const ctx = canvas.getContext("2d");
250
+ canvas.width = img.width;
251
+ canvas.height = img.height;
252
+ ctx?.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
253
+ return canvas;
254
+ }
255
+
256
+ /**
257
+ * 缩放图片
258
+ * @param img
259
+ * @param opt
260
+ * @returns base64
261
+ */
262
+ export function scaleImage(img: HTMLImageElement | HTMLCanvasElement, opt = { scaleFactor: 1 }) {
263
+ return scaleImageToCanvas(img, opt).toDataURL(IMAGE_TYPES.PNG, 1);
264
+ }
265
+
266
+ /**
267
+ * 缩放图片,返回 canvas
268
+ * @param img
269
+ * @param opt
270
+ * @returns canvas
271
+ */
272
+ export function scaleImageToCanvas(img: HTMLImageElement | HTMLCanvasElement, opt = { scaleFactor: 1 }) {
273
+ const { scaleFactor = 1 } = opt;
274
+ const canvas = document.createElement("canvas");
275
+ const ctx = canvas.getContext("2d");
276
+ canvas.width = img.width * scaleFactor;
277
+ canvas.height = img.height * scaleFactor;
278
+ ctx?.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
279
+ return canvas;
280
+ }
281
+
282
+ /**
283
+ * 图片转为 base64
284
+ * @param img
285
+ * @returns
286
+ */
287
+ export async function imgToBase64(img: string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement) {
288
+ if (!img || img instanceof Blob) {
289
+ return img;
290
+ }
291
+ let _img = img;
292
+ if (img instanceof Image) {
293
+ _img = img.src;
294
+ } else if (img instanceof HTMLVideoElement) {
295
+ // 从视频中获取图片
296
+ const canvas = document.createElement("canvas");
297
+ let { width, height } = getDomWH(img);
298
+ setDomWH(canvas, width, height);
299
+ const ctx = canvas.getContext("2d");
300
+ ctx && ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
301
+ _img = canvas.toDataURL(IMAGE_TYPES.PNG, 1);
302
+ } else if (img instanceof HTMLCanvasElement) {
303
+ _img = img.toDataURL(IMAGE_TYPES.PNG, 1);
304
+ } else if (typeof _img === "string" && !_img.startsWith("data:image/")) {
305
+ // 加载图片,并获取图片 base64
306
+ _img = await getImgBase64(_img);
307
+ }
308
+ return _img;
309
+ }
310
+
311
+ /**
312
+ * 图片转为 Blob
313
+ * @param img
314
+ * @returns
315
+ */
316
+ export async function imgToBlob(img: string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement): Promise<Blob> {
317
+ if (!img) {
318
+ throw new Error("请传入图片数据");
319
+ }
320
+ if (img instanceof Blob) {
321
+ return Promise.resolve(img);
322
+ }
323
+ const _img = await imgToBase64(img);
324
+ if (typeof _img !== "string") {
325
+ throw new Error("传入的图片数据不正确");
326
+ }
327
+ return dataURItoBlob(_img);
328
+ }
329
+
330
+ /**
331
+ * 获取图片的 base64、blob 格式
332
+ * @param img
333
+ */
334
+ export async function getAllTypeImg(img: string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement) {
335
+ const base64 = await imgToBase64(img);
336
+ return {
337
+ base64,
338
+ blob: typeof base64 === "string" && dataURItoBlob(base64),
339
+ };
340
+ }
341
+
342
+
343
+
344
+
345
+ /**
346
+ * 等比缩放图片尺寸(不裁切、不变形)
347
+ * @param {HTMLImageElement} img
348
+ * @param {number} scale 缩放比例 0~1
349
+ * @returns {Promise<Blob>}
350
+ */
351
+ export function drawScaleImage(img, scale) {
352
+ return new Promise((resolve) => {
353
+ const w = Math.round(img.width * scale);
354
+ const h = Math.round(img.height * scale);
355
+
356
+ const canvas = document.createElement("canvas");
357
+ canvas.width = w;
358
+ canvas.height = h;
359
+ const ctx = canvas.getContext("2d");
360
+
361
+ // 整图等比绘制,无裁切
362
+ ctx.drawImage(img, 0, 0, w, h);
363
+
364
+ canvas.toBlob((blob) => resolve(blob), "image/png");
365
+ });
366
+ }
367
+
368
+ /**
369
+ * JPG/WebP 仅动态降画质(不改尺寸)
370
+ * @param {Blob} blob
371
+ * @param {HTMLImageElement} img
372
+ * @returns {Promise<Blob>}
373
+ */
374
+ export function compressByQuality(blob, img, maxSize) {
375
+ return new Promise((resolve) => {
376
+ const canvas = document.createElement("canvas");
377
+ canvas.width = img.width;
378
+ canvas.height = img.height;
379
+ const ctx = canvas.getContext("2d");
380
+ ctx.drawImage(img, 0, 0);
381
+
382
+ let quality = 0.98;
383
+ const minQ = 0.5;
384
+
385
+ function loop() {
386
+ canvas.toBlob(
387
+ (newBlob) => {
388
+ if (newBlob.size <= maxSize || quality <= minQ) {
389
+ resolve(newBlob);
390
+ return;
391
+ }
392
+ quality -= 0.02;
393
+ loop();
394
+ },
395
+ blob.type,
396
+ quality,
397
+ );
398
+ }
399
+ loop();
400
+ });
401
+ }
402
+
403
+ /**
404
+ * 智能压缩入口
405
+ * 1. 小于10M直接返回原图
406
+ * 2. JPG/WebP:只降画质,不改尺寸
407
+ * 3. PNG:不转格式、只等比缩分辨率,不裁切
408
+ * @param {Blob} blob
409
+ * @returns {Promise<Blob>}
410
+ */
411
+ export function smartImageCompress(blob, maxSize) {
412
+ if (blob.size <= maxSize) {
413
+ return Promise.resolve(blob);
414
+ }
415
+
416
+ return new Promise((resolve) => {
417
+ const isPng = blob.type === "image/png";
418
+ const img = new Image();
419
+
420
+ img.src = URL.createObjectURL(blob);
421
+ img.onload = async () => {
422
+ URL.revokeObjectURL(img.src);
423
+
424
+ // 非PNG:只降画质
425
+ if (!isPng) {
426
+ const resBlob = await compressByQuality(blob, img, maxSize);
427
+ return resolve(resBlob);
428
+ }
429
+
430
+ // PNG:只等比缩分辨率,不转格式、不裁切
431
+ let scale = 0.95; // 每次缩小5%
432
+ const minScale = 0.5; // 最低缩到原图50%,不再缩
433
+
434
+ let currentBlob = blob;
435
+
436
+ const loopScale = async () => {
437
+ currentBlob = await drawScaleImage(img, scale);
438
+
439
+ if (currentBlob.size <= maxSize || scale <= minScale) {
440
+ resolve(currentBlob);
441
+ return;
442
+ }
443
+
444
+ scale -= 0.05;
445
+
446
+ loopScale();
447
+ };
448
+
449
+ loopScale();
450
+ };
451
+ });
452
+ }
453
+
454
+
455
+
456
+
package/src/scan-qr.ts CHANGED
@@ -64,7 +64,7 @@ const setCodeInfo = async (
64
64
  try {
65
65
  const id = nanoidUrl();
66
66
  const file = objToBlob(value) as File;
67
- const ossUploader = new OssUploads();
67
+ const ossUploader = new OssUploads({signatureParams: {withoutPrefix: true}});
68
68
  const uploadResult = await ossUploader.upload(file, {
69
69
  fileName: id,
70
70
  params: {
@@ -1,214 +1,218 @@
1
- import dayjs from "dayjs";
2
- import { Axios, AxiosResponse, AxiosRequestConfig } from "axios";
3
-
4
- import { axios } from "@hzab/data-model";
5
- import { formatDirStr } from "./uploadUtils";
6
- import { getGlobalServeConfig } from "../globalConfig";
7
- const isPublicMap = {
8
- 0: "&",
9
- 1: "?",
10
- };
11
- /**
12
- * getSignature 配置
13
- */
14
- export interface IGetSignatureOpt {
15
- /** 获取配置的接口地址 */
16
- serverUrl?: string;
17
- /** axios 实例 */
18
- axios?: Axios;
19
- /** axios 配置参数 */
20
- axiosConf?: AxiosRequestConfig;
21
- /** 获取配置的接口自定义入参 */
22
- params?: {
23
- /** 文件路径 */
24
- dir?: string;
25
- /** 是否是公开库 */
26
- isPublic?: number;
27
- };
28
- }
29
-
30
- /**
31
- * OssUpload props 参数
32
- */
33
- export interface IOssUploadProps {
34
- /** axios 实例 */
35
- axios?: Axios;
36
- /** axios 配置参数 */
37
- axiosConf?: AxiosRequestConfig;
38
- /** 获取配置的接口地址 */
39
- serverUrl?: string;
40
- /** 获取配置的接口自定义入参 */
41
- signatureParams?: {
42
- /** 文件路径 */
43
- dir?: string;
44
- /** 是否是公开库 */
45
- isPublic?: number;
46
- };
47
- }
48
-
49
- export interface IUploadOpt {
50
- fileName?: string;
51
- /** axios 实例 */
52
- axios?: Axios;
53
- /** axios 配置参数 */
54
- axiosConf?: AxiosRequestConfig;
55
- /** 获取配置的接口地址 */
56
- serverUrl?: string;
57
- /** 获取配置的接口自定义入参 */
58
- params?: {
59
- /** 文件路径 */
60
- dir?: string;
61
- /** 是否是公开库 */
62
- isPublic?: number;
63
- };
64
- /**
65
- * 获取配置接口请求入参
66
- */
67
- signatureParams?: {
68
- /** 公开还是私有 */
69
- isPublic?: number;
70
- };
71
- /** 文件上传的接口自定义入参 */
72
- ossParams?: {};
73
- /** 是否使用 hash 文件名 */
74
- useHashName?: boolean;
75
- /**缩略图参数 */
76
- thumbnailParams?: string;
77
- }
78
-
79
- export interface ResponseData extends AxiosResponse {
80
- fileUrl: string;
81
- thumbnailUrl?: string;
82
- }
83
-
84
- export function getSignature(opt: IGetSignatureOpt = {}) {
85
- const { serverUrl = getGlobalServeConfig()?.serverUrl || "/api/v1/user/oss/getWebOssConfig" } = opt;
86
- // 10 秒,避免发起请求时 刚好过期的情况
87
- if (
88
- window._$ossSignatureRes &&
89
- serverUrl === window._$ossSignatureRes.serverUrl &&
90
- dayjs().valueOf() - window._$ossSignatureRes.__saveTime < window._$ossSignatureRes.expireTimeMilles - 10000
91
- ) {
92
- return Promise.resolve(window._$ossSignatureRes);
93
- }
94
- const { axios: _ax = axios, params = {}, axiosConf } = opt;
95
- // 处理 dir 格式,必须为非 / 开头, / 结尾。如: test/
96
- params.dir = formatDirStr(params.dir);
97
-
98
- return _ax
99
- .get(serverUrl, {
100
- ...axiosConf,
101
- params: {
102
- isPublic: 1,
103
- ...params,
104
- },
105
- })
106
- .then((res) => {
107
- window._$ossSignatureRes = res?.data?.data ?? res?.data ?? res;
108
- if (window._$ossSignatureRes) {
109
- window._$ossSignatureRes.__saveTime = dayjs().valueOf();
110
- window._$ossSignatureRes.serverUrl = serverUrl;
111
- }
112
- return window._$ossSignatureRes;
113
- });
114
- }
115
-
116
- /**
117
- * oss 上传工具类
118
- */
119
- class OssUploadUtil {
120
- /** axios 实例 */
121
- axios: Axios;
122
- /** axios 配置参数 */
123
- axiosConf: AxiosRequestConfig;
124
- /** 获取配置的接口地址 */
125
- serverUrl: string;
126
- /** 获取配置的接口自定义入参 */
127
- signatureParams?: {
128
- /** 文件路径 */
129
- dir?: string;
130
- /** 是否是公开库 */
131
- isPublic?: number;
132
- };
133
-
134
- constructor(props: IOssUploadProps = {}) {
135
- this.axios = props.axios || axios;
136
- this.axiosConf = props.axiosConf || {};
137
- this.serverUrl = props.serverUrl || getGlobalServeConfig()?.serverUrl || "/api/v1/user/oss/getWebOssConfig";
138
- this.signatureParams = props.signatureParams || {};
139
- }
140
-
141
- getSignature(serverUrl = this.serverUrl, opt) {
142
- return this._getSignature(serverUrl, opt);
143
- }
144
-
145
- upload(file, opt: IUploadOpt = {}): Promise<{ fileUrl: string }> {
146
- return this._upload(file, { ...opt });
147
- }
148
-
149
- _getSignature(serverUrl = this.serverUrl, opt) {
150
- return getSignature({
151
- ...opt,
152
- serverUrl,
153
- axios: opt?.axios || this.axios,
154
- axiosConf: { ...this.axiosConf, ...opt?.axiosConf },
155
- });
156
- }
157
-
158
- _upload(file, opt: IUploadOpt = {}): Promise<{ fileUrl: string }> {
159
- return new Promise(async (resolve, reject) => {
160
- const ossParams = await this._getSignature(opt.serverUrl || this.serverUrl, {
161
- ...opt,
162
- params: { ...this.signatureParams, ...opt.params },
163
- });
164
-
165
- const { ossParams: propOssParams, fileName } = opt || {};
166
- const formData = new FormData();
167
- // key 表示上传到 Bucket 内的 Object 的完整路径,例如 exampledir/exampleobject.txtObject,完整路径中不能包含 Bucket 名称。
168
- // filename 表示待上传的本地文件名称。
169
- const filename = fileName || file.name;
170
- const key = `${ossParams?.dir}${filename}`;
171
- formData.set("key", key);
172
- formData.set("OSSAccessKeyId", ossParams.accessid);
173
- formData.set("policy", ossParams.policy);
174
- formData.set("Signature", ossParams.signature);
175
- if (ossParams.callback) {
176
- formData.set("callback", ossParams.callback);
177
- }
178
- // @ts-ignore
179
- formData.set("success_action_status", 200);
180
- formData.set("file", file);
181
-
182
- if (propOssParams) {
183
- for (const key in propOssParams) {
184
- if (Object.hasOwnProperty.call(propOssParams, key)) {
185
- formData.set(key, propOssParams[key]);
186
- }
187
- }
188
- }
189
-
190
- const _axios = opt?.axios || this.axios;
191
-
192
- return _axios
193
- .post(ossParams.host, formData, { ...this.axiosConf, ...opt?.axiosConf })
194
- .then((res: ResponseData) => {
195
- if (getGlobalServeConfig()?.showThumbnail) {
196
- res.data.data.thumbnailUrl = `${res?.data?.data?.fileUrl}${
197
- opt?.thumbnailParams ? isPublicMap[opt?.signatureParams?.isPublic] + opt?.thumbnailParams : ""
198
- }`;
199
- }
200
- resolve(res);
201
- return res;
202
- })
203
- .catch((err) => {
204
- console.error("oss upload err", err);
205
- reject(err);
206
- return Promise.reject(err);
207
- });
208
- });
209
- }
210
- }
211
-
212
- export { axios };
213
-
214
- export default OssUploadUtil;
1
+ import dayjs from "dayjs";
2
+ import { Axios, AxiosResponse, AxiosRequestConfig } from "axios";
3
+
4
+ import { axios } from "@hzab/data-model";
5
+ import { formatDirStr } from "./uploadUtils";
6
+ import { getGlobalServeConfig } from "../globalConfig";
7
+ const isPublicMap = {
8
+ 0: "&",
9
+ 1: "?",
10
+ };
11
+ /**
12
+ * getSignature 配置
13
+ */
14
+ export interface IGetSignatureOpt {
15
+ /** 获取配置的接口地址 */
16
+ serverUrl?: string;
17
+ /** axios 实例 */
18
+ axios?: Axios;
19
+ /** axios 配置参数 */
20
+ axiosConf?: AxiosRequestConfig;
21
+ /** 获取配置的接口自定义入参 */
22
+ params?: {
23
+ /** 文件路径 */
24
+ dir?: string;
25
+ /** 是否是公开库 */
26
+ isPublic?: number;
27
+ };
28
+ }
29
+
30
+ /**
31
+ * OssUpload props 参数
32
+ */
33
+ export interface IOssUploadProps {
34
+ /** axios 实例 */
35
+ axios?: Axios;
36
+ /** axios 配置参数 */
37
+ axiosConf?: AxiosRequestConfig;
38
+ /** 获取配置的接口地址 */
39
+ serverUrl?: string;
40
+ /** 获取配置的接口自定义入参 */
41
+ signatureParams?: {
42
+ /** 文件路径 */
43
+ dir?: string;
44
+ /** 是否是公开库 */
45
+ isPublic?: number;
46
+ /** 是否无前缀 */
47
+ withoutPrefix?: boolean;
48
+ };
49
+ }
50
+
51
+ export interface IUploadOpt {
52
+ fileName?: string;
53
+ /** axios 实例 */
54
+ axios?: Axios;
55
+ /** axios 配置参数 */
56
+ axiosConf?: AxiosRequestConfig;
57
+ /** 获取配置的接口地址 */
58
+ serverUrl?: string;
59
+ /** 获取配置的接口自定义入参 */
60
+ params?: {
61
+ /** 文件路径 */
62
+ dir?: string;
63
+ /** 是否是公开库 */
64
+ isPublic?: number;
65
+ };
66
+ /**
67
+ * 获取配置接口请求入参
68
+ */
69
+ signatureParams?: {
70
+ /** 公开还是私有 */
71
+ isPublic?: number;
72
+ };
73
+ /** 文件上传的接口自定义入参 */
74
+ ossParams?: {};
75
+ /** 是否使用 hash 文件名 */
76
+ useHashName?: boolean;
77
+ /**缩略图参数 */
78
+ thumbnailParams?: string;
79
+ }
80
+
81
+ export interface ResponseData extends AxiosResponse {
82
+ fileUrl: string;
83
+ thumbnailUrl?: string;
84
+ }
85
+
86
+ export function getSignature(opt: IGetSignatureOpt = {}) {
87
+ const { serverUrl = getGlobalServeConfig()?.serverUrl || "/api/v1/user/oss/getWebOssConfig" } = opt;
88
+ // 减 10 秒,避免发起请求时 刚好过期的情况
89
+ if (
90
+ window._$ossSignatureRes &&
91
+ serverUrl === window._$ossSignatureRes.serverUrl &&
92
+ dayjs().valueOf() - window._$ossSignatureRes.__saveTime < window._$ossSignatureRes.expireTimeMilles - 10000
93
+ ) {
94
+ return Promise.resolve(window._$ossSignatureRes);
95
+ }
96
+ const { axios: _ax = axios, params = {}, axiosConf } = opt;
97
+ // 处理 dir 格式,必须为非 / 开头, / 结尾。如: test/
98
+ params.dir = formatDirStr(params.dir);
99
+
100
+ return _ax
101
+ .get(serverUrl, {
102
+ ...axiosConf,
103
+ params: {
104
+ isPublic: 1,
105
+ ...params,
106
+ },
107
+ })
108
+ .then((res) => {
109
+ window._$ossSignatureRes = res?.data?.data ?? res?.data ?? res;
110
+ if (window._$ossSignatureRes) {
111
+ window._$ossSignatureRes.__saveTime = dayjs().valueOf();
112
+ window._$ossSignatureRes.serverUrl = serverUrl;
113
+ }
114
+ return window._$ossSignatureRes;
115
+ });
116
+ }
117
+
118
+ /**
119
+ * oss 上传工具类
120
+ */
121
+ class OssUploadUtil {
122
+ /** axios 实例 */
123
+ axios: Axios;
124
+ /** axios 配置参数 */
125
+ axiosConf: AxiosRequestConfig;
126
+ /** 获取配置的接口地址 */
127
+ serverUrl: string;
128
+ /** 获取配置的接口自定义入参 */
129
+ signatureParams?: {
130
+ /** 文件路径 */
131
+ dir?: string;
132
+ /** 是否是公开库 */
133
+ isPublic?: number;
134
+ /** 是否无前缀 */
135
+ withoutPrefix?: boolean;
136
+ };
137
+
138
+ constructor(props: IOssUploadProps = {}) {
139
+ this.axios = props.axios || axios;
140
+ this.axiosConf = props.axiosConf || {};
141
+ this.serverUrl = props.serverUrl || getGlobalServeConfig()?.serverUrl || "/api/v1/user/oss/getWebOssConfig";
142
+ this.signatureParams = props.signatureParams || {};
143
+ }
144
+
145
+ getSignature(serverUrl = this.serverUrl, opt) {
146
+ return this._getSignature(serverUrl, opt);
147
+ }
148
+
149
+ upload(file, opt: IUploadOpt = {}): Promise<{ fileUrl: string }> {
150
+ return this._upload(file, { ...opt });
151
+ }
152
+
153
+ _getSignature(serverUrl = this.serverUrl, opt) {
154
+ return getSignature({
155
+ ...opt,
156
+ serverUrl,
157
+ axios: opt?.axios || this.axios,
158
+ axiosConf: { ...this.axiosConf, ...opt?.axiosConf },
159
+ });
160
+ }
161
+
162
+ _upload(file, opt: IUploadOpt = {}): Promise<{ fileUrl: string }> {
163
+ return new Promise(async (resolve, reject) => {
164
+ const ossParams = await this._getSignature(opt.serverUrl || this.serverUrl, {
165
+ ...opt,
166
+ params: { ...this.signatureParams, ...opt.params },
167
+ });
168
+
169
+ const { ossParams: propOssParams, fileName } = opt || {};
170
+ const formData = new FormData();
171
+ // key 表示上传到 Bucket 内的 Object 的完整路径,例如 exampledir/exampleobject.txtObject,完整路径中不能包含 Bucket 名称。
172
+ // filename 表示待上传的本地文件名称。
173
+ const filename = fileName || file.name;
174
+ const key = `${ossParams?.dir}${filename}`;
175
+ formData.set("key", key);
176
+ formData.set("OSSAccessKeyId", ossParams.accessid);
177
+ formData.set("policy", ossParams.policy);
178
+ formData.set("Signature", ossParams.signature);
179
+ if (ossParams.callback) {
180
+ formData.set("callback", ossParams.callback);
181
+ }
182
+ // @ts-ignore
183
+ formData.set("success_action_status", 200);
184
+ formData.set("file", file);
185
+
186
+ if (propOssParams) {
187
+ for (const key in propOssParams) {
188
+ if (Object.hasOwnProperty.call(propOssParams, key)) {
189
+ formData.set(key, propOssParams[key]);
190
+ }
191
+ }
192
+ }
193
+
194
+ const _axios = opt?.axios || this.axios;
195
+
196
+ return _axios
197
+ .post(ossParams.host, formData, { ...this.axiosConf, ...opt?.axiosConf })
198
+ .then((res: ResponseData) => {
199
+ if (getGlobalServeConfig()?.showThumbnail) {
200
+ res.data.data.thumbnailUrl = `${res?.data?.data?.fileUrl}${
201
+ opt?.thumbnailParams ? isPublicMap[opt?.signatureParams?.isPublic] + opt?.thumbnailParams : ""
202
+ }`;
203
+ }
204
+ resolve(res);
205
+ return res;
206
+ })
207
+ .catch((err) => {
208
+ console.error("oss upload err", err);
209
+ reject(err);
210
+ return Promise.reject(err);
211
+ });
212
+ });
213
+ }
214
+ }
215
+
216
+ export { axios };
217
+
218
+ export default OssUploadUtil;