jack 4 недель назад
Родитель
Сommit
dba66d744b
1 измененных файлов с 52 добавлено и 37 удалено
  1. 52 37
      src/hooks/useImport.ts

+ 52 - 37
src/hooks/useImport.ts

@@ -513,82 +513,97 @@ export default () => {
     filename: string,
     options?: { tolerance?: number }
   ): Promise<File> => {
-    const tolerance = options?.tolerance ?? 15 // 只处理非常接近白色的像素
-
-    // 1. 将输入统一转为可加载的 URL
-    let imageUrl: string
-    let needRevoke = false
-
-    if (typeof data === 'string') {
-      imageUrl = data.startsWith('data:') ? data : `data:image/png;base64,${data}`
-    }
-    else if (data instanceof Blob) {
-      imageUrl = URL.createObjectURL(data)
-      needRevoke = true
+    const tolerance = options?.tolerance ?? 15
+  
+    // ----- 辅助函数:将输入统一转换为 { blob, mime } -----
+    async function getBlobAndMime(input: string | Blob): Promise<{ blob: Blob; mime: string }> {
+      // 1. 已经是 Blob
+      if (input instanceof Blob) {
+        return { blob: input, mime: input.type }
+      }
+  
+      // 2. 处理字符串
+      if (input.startsWith('data:')) {
+        // data URL → 通过 fetch 获取 Blob(自动获得正确的 MIME 类型)
+        const response = await fetch(input)
+        const blob = await response.blob()
+        return { blob, mime: blob.type }
+      } else {
+        // 纯 base64 字符串 → 按原逻辑默认当作 PNG
+        const binary = atob(input)
+        const bytes = new Uint8Array(binary.length)
+        for (let i = 0; i < binary.length; i++) {
+          bytes[i] = binary.charCodeAt(i)
+        }
+        // 默认 MIME 为 image/png(与原函数行为一致)
+        const blob = new Blob([bytes], { type: 'image/png' })
+        return { blob, mime: 'image/png' }
+      }
     }
-    else {
-      throw new Error('Unsupported data type: expected string or Blob')
+  
+    // 获取统一的 blob 和实际 MIME 类型
+    const { blob, mime } = await getBlobAndMime(data)
+  
+    // ----- 非 PNG 格式:直接返回原始文件(不处理透明)-----
+    if (mime !== 'image/png') {
+      return new File([blob], filename, { type: mime })
     }
+  
+    // ----- PNG 格式:执行白色变透明处理 -----
+    // 1. 创建对象 URL 用于加载图片
+    const imageUrl = URL.createObjectURL(blob)
+    let needRevoke = true
+  
     // 2. 加载图像
     const img = await new Promise<HTMLImageElement>((resolve, reject) => {
       const image = new Image()
       image.onload = () => resolve(image)
       image.onerror = reject
-      if (typeof data === 'string' && !data.startsWith('data:')) {
-        image.crossOrigin = 'anonymous'
-      }
+      // Blob URL 不需要设置 crossOrigin
       image.src = imageUrl
     })
+  
     const canvas = document.createElement('canvas')
     try {
-      // 3. 绘制到 Canvas
       canvas.width = img.width
       canvas.height = img.height
       const ctx = canvas.getContext('2d')!
       ctx.drawImage(img, 0, 0)
-
-      // 4. 获取像素数据
+  
+      // 3. 获取像素数据,将接近白色的像素设为透明
       const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
       const dataArray = imageData.data
-
-      // 5. 遍历像素:只将白色背景区域设为透明,其他颜色原样保留
+  
       for (let i = 0; i < dataArray.length; i += 4) {
         const r = dataArray[i]
         const g = dataArray[i + 1]
         const b = dataArray[i + 2]
-
-        // 计算与纯白色 (255,255,255) 的欧几里得距离
+  
         const dr = r - 255
         const dg = g - 255
         const db = b - 255
         const dist = Math.sqrt(dr * dr + dg * dg + db * db)
-
+  
         if (dist <= tolerance) {
-          // 非常接近白色 → 设为全透明
-          dataArray[i + 3] = 0
+          dataArray[i + 3] = 0 // 完全透明
         }
-        // 其他所有像素(包括浅蓝、灰色、黑色等)保持原样,不修改颜色和透明度
       }
-
-      // 6. 将修改后的像素放回 Canvas
+  
       ctx.putImageData(imageData, 0, 0)
-
-
-    }
-    finally {
+    } finally {
       if (needRevoke) {
         URL.revokeObjectURL(imageUrl)
       }
     }
-    // 7. 导出为 PNG Blob
+  
+    // 4. 导出为 PNG Blob
     const outputBlob = await new Promise<Blob>((resolve, reject) => {
       canvas.toBlob((blob) => {
         if (blob) resolve(blob)
         else reject(new Error('Canvas toBlob failed'))
       }, 'image/png')
     })
-
-    // 8. 返回 File 对象
+  
     return new File([outputBlob], filename, { type: 'image/png' })
   }