diff --git a/app/src/menus/protyle.ts b/app/src/menus/protyle.ts index 2077013d7..f37ba244f 100644 --- a/app/src/menus/protyle.ts +++ b/app/src/menus/protyle.ts @@ -63,6 +63,7 @@ import {img3115} from "../boot/compatibleVersion"; import {hideTooltip} from "../dialog/tooltip"; import {clearSelect} from "../protyle/util/clear"; import {scrollCenter} from "../util/highlightById"; +import {base64ToURL} from "../util/image"; const renderAssetList = (element: Element, k: string, position: IPosition, exts: string[] = []) => { fetchPost("/api/search/searchAsset", { @@ -1444,28 +1445,11 @@ export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLEleme textElements[0].select(); } window.siyuan.menus.menu.removeCB = async () => { - const srcPart = textElements[0].value.split(","); - if (src !== textElements[0].value && srcPart.length > 1 && srcPart[0].startsWith("data:image/")) { - // data:image/svg+xml;base64,XXX - const mimeMatch = srcPart[0].match(/data:([^;]+);/); - const mime = mimeMatch ? mimeMatch[1] : "application/octet-stream"; - const binary = atob(srcPart[1]); - const u8arr = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) { - u8arr[i] = binary.charCodeAt(i); - } - const formData = new FormData(); - formData.append("file[]", new File([u8arr], `base64image.${{ - "image/png": "png", - "image/jpeg": "jpg", - "image/webp": "webp", - "image/gif": "gif", - "image/svg+xml": "svg" - }[mime] || "png"}`, {type: mime})); - const response = await fetchSyncPost(Constants.UPLOAD_ADDRESS, formData); - const base64Src = response.data.succMap[Object.keys(response.data.succMap)[0]]; - imgElement.setAttribute("src", base64Src); - imgElement.setAttribute("data-src", base64Src); + const newSrc = textElements[0].value; + if (src !== newSrc && newSrc.startsWith("data:image/")) { + const base64Src = await base64ToURL([newSrc]); + imgElement.setAttribute("src", base64Src[0]); + imgElement.setAttribute("data-src", base64Src[0]); assetElement.querySelector(".img__net")?.remove(); } diff --git a/app/src/protyle/util/paste.ts b/app/src/protyle/util/paste.ts index c00403f70..e5593b41f 100644 --- a/app/src/protyle/util/paste.ts +++ b/app/src/protyle/util/paste.ts @@ -16,6 +16,7 @@ import {cellScrollIntoView, getCellText} from "../render/av/cell"; import {getCalloutInfo, getContenteditableElement} from "../wysiwyg/getBlock"; import {clearBlockElement} from "./clear"; import {removeZWJ} from "./normalizeText"; +import {base64ToURL} from "../../util/image"; export const getTextStar = (blockElement: HTMLElement, contentOnly = false) => { const dataType = blockElement.dataset.type; @@ -593,7 +594,25 @@ export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEven } } } - const textPlainDom = protyle.lute.Md2BlockDOM(textPlain); + let textPlainDom = protyle.lute.Md2BlockDOM(textPlain); + if (textPlainDom && textPlainDom.indexOf("data:image/") > -1) { + const tempElement = document.createElement("template"); + tempElement.innerHTML = textPlainDom; + const imgSrcList: string[] = []; + const imageElements = tempElement.content.querySelectorAll("img"); + imageElements.forEach((item) => { + if (item.getAttribute("data-src").startsWith("data:image/")) { + imgSrcList.push(item.getAttribute("data-src")); + } + }); + const base64SrcList = await base64ToURL(imgSrcList); + base64SrcList.forEach((item, index) => { + imageElements[index].setAttribute("src", item); + imageElements[index].setAttribute("data-src", item); + imageElements[index].parentElement.querySelector(".img__net")?.remove(); + }); + textPlainDom = tempElement.innerHTML; + } insertHTML(textPlainDom, protyle, false, false, true); } blockRender(protyle, protyle.wysiwyg.element); diff --git a/app/src/util/image.ts b/app/src/util/image.ts index 9c9c83ea9..d500e9ace 100644 --- a/app/src/util/image.ts +++ b/app/src/util/image.ts @@ -1,3 +1,6 @@ +import {fetchSyncPost} from "./fetch"; +import {Constants} from "../constants"; + export const getCompressURL = (url: string) => { if (url.startsWith("assets/") && (url.endsWith(".png") || url.endsWith(".jpg") || url.endsWith(".jpeg"))) { @@ -13,3 +16,32 @@ export const removeCompressURL = (url: string) => { } return url; }; + +export const base64ToURL = async (base64SrcList: string[]) => { + const formData = new FormData(); + base64SrcList.forEach(item => { + const srcPart = item.split(","); + if (srcPart.length !== 2) return; + // data:image/svg+xml;base64,XXX + const mimeMatch = srcPart[0].match(/data:([^;]+);/); + const mime = mimeMatch ? mimeMatch[1] : "application/octet-stream"; + const binary = atob(srcPart[1]); + const u8arr = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + u8arr[i] = binary.charCodeAt(i); + } + formData.append("file[]", new File([u8arr], `base64image.${{ + "image/png": "png", + "image/jpeg": "jpg", + "image/webp": "webp", + "image/gif": "gif", + "image/svg+xml": "svg" + }[mime] || "png"}`, {type: mime})); + }); + const response = await fetchSyncPost(Constants.UPLOAD_ADDRESS, formData); + const URLs: string[] = []; + Object.keys(response.data.succMap).forEach((item) => { + URLs.push(response.data.succMap[item]); + }); + return URLs; +};