gaoluyang
2026-06-29 27cd042df9aca0383a49f3514bc21958dd890912
src/views/im/utils/image.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
// ====================================================================
// IM å›¾ç‰‡å·¥å…·
// ====================================================================
// - probeImageSize:加载本地 File æˆ–远程 URL,读出 naturalWidth / naturalHeight
// - loadImage:加载远程 URL åˆ° HTMLImageElement(失败返回 null,不抛错),供 canvas ç»˜åˆ¶ä½¿ç”¨
// ====================================================================
/** é»˜è®¤å ä½å°ºå¯¸ï¼šprobe å¤±è´¥ / è§£ç å¼‚常时兜底,避免 width/height ä¸º 0 è®©æ¶ˆæ¯æ¸²æŸ“塌掉 */
const DEFAULT_FALLBACK_SIZE = { width: 200, height: 200 } as const
/** åŠ è½½è¿œç¨‹ URL åˆ° HTMLImageElement,失败返回 null;canvas ç»˜åˆ¶è¦æ±‚ crossOrigin=anonymous(默认开) */
export function loadImage(
  src: string,
  options: { crossOrigin?: 'anonymous' | 'use-credentials' | null } = {}
): Promise<HTMLImageElement | null> {
  const crossOrigin = options.crossOrigin === undefined ? 'anonymous' : options.crossOrigin
  return new Promise((resolve) => {
    const img = new Image()
    if (crossOrigin) {
      img.crossOrigin = crossOrigin
    }
    img.addEventListener('load', () => resolve(img))
    img.addEventListener('error', () => resolve(null))
    img.src = src
  })
}
/**
 * åŠ è½½æœ¬åœ° File æˆ–远程 URL,解出 naturalWidth / naturalHeight
 *
 * - File:内部 createObjectURL + revokeObjectURL,避免内存累积
 * - è¿œç¨‹ URL:直接走 <img>.src è§¦å‘浏览器加载(受 CORS å½±å“ï¼›åªè¯»å°ºå¯¸ä¸éœ€è¦ç”» canvas,跨域也能拿到)
 * - è§£ç å¤±è´¥ / ä¸æ˜¯å›¾ç‰‡ï¼šè¿”回 200×200 å…œåº•
 */
export function probeImageSize(source: File | string): Promise<{ height: number; width: number; }> {
  const isFile = source instanceof File
  const src = isFile ? URL.createObjectURL(source) : source
  return new Promise((resolve) => {
    const img = new Image()
    img.addEventListener('load', () => {
      if (isFile) {
        URL.revokeObjectURL(src)
      }
      resolve({
        width: img.naturalWidth || DEFAULT_FALLBACK_SIZE.width,
        height: img.naturalHeight || DEFAULT_FALLBACK_SIZE.height
      })
    })
    img.addEventListener('error', () => {
      if (isFile) {
        URL.revokeObjectURL(src)
      }
      resolve({ ...DEFAULT_FALLBACK_SIZE })
    })
    img.src = src
  })
}