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 { 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 { 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 { 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); }); }); }