diff --git a/package.json b/package.json index 89989bf4..d93f017a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vocechat-web", - "version": "0.4.5", + "version": "0.4.6", "homepage": "https://voce.chat", "dependencies": { "@emoji-mart/react": "^1.1.1", @@ -35,6 +35,7 @@ "firebase": "^9.22.1", "framer-motion": "^10.12.16", "fs-extra": "^11.1.1", + "heic2any": "^0.0.4", "html-webpack-plugin": "^5.5.1", "i18next": "^22.5.0", "i18next-browser-languagedetector": "^7.0.2", diff --git a/src/hooks/useUploadFile.ts b/src/hooks/useUploadFile.ts index 2a46e9d6..94100f67 100644 --- a/src/hooks/useUploadFile.ts +++ b/src/hooks/useUploadFile.ts @@ -1,5 +1,6 @@ import { useRef, useState } from "react"; import toast from "react-hot-toast"; +import heic2any from "heic2any"; import BASE_URL, { FILE_SLICE_SIZE } from "@/app/config"; import { usePrepareUploadFileMutation, useUploadFileMutation } from "@/app/services/message"; @@ -9,10 +10,27 @@ import { Message } from "@/types/channel"; import { ChatContext } from "@/types/common"; import { UploadFileResponse } from "@/types/message"; +export type UploadFileData = { + name: string; + type: string; + size: number; + url: string; +}; interface IProps { context: ChatContext; id: number; } +const convertHeic2Jpg = async (file: { name: string; type: string; size: number; url: string }) => { + const res = await fetch(file.url); + const blob = await res.blob(); + const jpgBlob = (await heic2any({ + blob, + toType: "image/jpeg", + quality: 0.8 + })) as Blob; + const newName = file.name.replace(/\.hei\w$/i, ".jpg"); + return { ...file, name: newName, url: URL.createObjectURL(jpgBlob) }; +}; const useUploadFile = (props?: IProps) => { const { context, id } = props ? props : { context: "channel", id: 0 }; const dispatch = useAppDispatch(); @@ -50,6 +68,8 @@ const useUploadFile = (props?: IProps) => { type: file_type, size: file_size } = file; + console.log("file type", file_type); + // 生成 file id const resp = await prepareUploadFile({ content_type: file_type, @@ -128,12 +148,25 @@ const useUploadFile = (props?: IProps) => { dispatch(updateUploadFiles({ context, id, operation: "remove", index: idx })); }; - const addStageFile = (fileData = {}) => { + const addStageFile = (filesData: UploadFileData[]) => { if (replying) { toast.error("Only text is supported when replying a message"); return; } - dispatch(updateUploadFiles({ context, id, data: fileData })); + const hasHeif = filesData.some((f) => f.type.startsWith("image/hei")); + console.log("heif test", filesData, hasHeif); + if (hasHeif) { + const hFiles = filesData.filter((f) => f.type.startsWith("image/hei")); + Promise.all(hFiles.map((f) => convertHeic2Jpg(f))).then((res) => { + console.log("heif2jpg", res); + const nonHeifFiles = filesData.filter((f) => !f.type.startsWith("image/hei")); + const newFilesData = [...nonHeifFiles, ...res]; + dispatch(updateUploadFiles({ context, id, data: newFilesData })); + }); + } else { + dispatch(updateUploadFiles({ context, id, data: filesData })); + } + // const data= }; const resetStageFiles = () => { diff --git a/yarn.lock b/yarn.lock index 9b1fdde7..f691307d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7086,6 +7086,11 @@ he@^1.2.0: resolved "https://mirrors.cloud.tencent.com/npm/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +heic2any@^0.0.4: + version "0.0.4" + resolved "https://mirrors.cloud.tencent.com/npm/heic2any/-/heic2any-0.0.4.tgz#eddb8e6fec53c8583a6e18b65069bb5e8d19028a" + integrity sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA== + highlight.js@^10.4.1, highlight.js@~10.7.0: version "10.7.3" resolved "https://mirrors.cloud.tencent.com/npm/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"