cropImage16x9.ts
3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import type { ComponentPublicInstance } from "vue";
/** 较小分辨率 + 二次 compressImage,适配常见 php.ini 默认 2M 上限 */
const DEST_W = 640;
const DEST_H = 360;
/**
* 将图片按中心裁剪为 16:9,输出约 640×360 JPEG(仅接受横向原图:宽大于高)。
* - H5:canvas + Blob URL(供 uni.uploadFile)
* - 微信小程序:依赖页面内 canvas-id="crop16" 与传入的组件实例
* - 其他端:原图返回
*/
export function cropImageTo16x9(
src: string,
mpInstance?: ComponentPublicInstance | null
): Promise<string> {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src,
success: (info) => {
const iw = info.width;
const ih = info.height;
if (iw <= ih) {
reject(new Error("请上传横向照片(宽需大于高),竖图或方图无法使用"));
return;
}
const ar = 16 / 9;
let sx = 0;
let sy = 0;
let sw = iw;
let sh = ih;
if (iw / ih > ar) {
sw = Math.round(ih * ar);
sx = Math.round((iw - sw) / 2);
} else {
sh = Math.round(iw / ar);
sy = Math.round((ih - sh) / 2);
}
const plat = String(
(import.meta as unknown as { env?: { UNI_PLATFORM?: string } }).env
?.UNI_PLATFORM ?? ""
);
if (plat === "h5" || plat === "web") {
cropH5(src, sx, sy, sw, sh).then(resolve).catch(reject);
return;
}
if (plat === "mp-weixin" && mpInstance) {
cropMpWx(src, sx, sy, sw, sh, mpInstance).then(resolve).catch(reject);
return;
}
resolve(src);
},
fail: (e) => reject(e),
});
});
}
function cropH5(
src: string,
sx: number,
sy: number,
sw: number,
sh: number
): Promise<string> {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => {
try {
const canvas = document.createElement("canvas");
canvas.width = DEST_W;
canvas.height = DEST_H;
const ctx = canvas.getContext("2d");
if (!ctx) {
reject(new Error("canvas"));
return;
}
ctx.drawImage(img, sx, sy, sw, sh, 0, 0, DEST_W, DEST_H);
canvas.toBlob(
(blob) => {
if (!blob) {
reject(new Error("toBlob"));
return;
}
resolve(URL.createObjectURL(blob));
},
"image/jpeg",
0.68
);
} catch (e) {
reject(e);
}
};
img.onerror = () => reject(new Error("图片加载失败"));
img.src = src;
});
}
function cropMpWx(
src: string,
sx: number,
sy: number,
sw: number,
sh: number,
instance: ComponentPublicInstance
): Promise<string> {
return new Promise((resolve, reject) => {
const ctx = uni.createCanvasContext("crop16", instance as any);
ctx.drawImage(src, sx, sy, sw, sh, 0, 0, DEST_W, DEST_H);
ctx.draw(false, () => {
setTimeout(() => {
uni.canvasToTempFilePath(
{
canvasId: "crop16",
destWidth: DEST_W,
destHeight: DEST_H,
fileType: "jpg",
quality: 0.68,
success: (r) => resolve(r.tempFilePath),
fail: (e) => reject(e),
},
instance as any
);
}, 150);
});
});
}