import { Canvg, presets } from "canvg" // https://gist.githubusercontent.com/n1ru4l/9c7eff52fe084d67ff15ae6b0af5f171/raw/da9fe36d72171d4e36b92aced587b48dc5182792/offscreen-canvas-polyfill.js // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore if (!window.OffscreenCanvas) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.OffscreenCanvas = class OffscreenCanvas { canvas: HTMLCanvasElement constructor(width: number, height: number) { this.canvas = document.createElement("canvas") this.canvas.width = width this.canvas.height = height // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.canvas.convertToBlob = () => { return new Promise(resolve => { this.canvas.toBlob(resolve) }) } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return this.canvas } } } const preset: any = presets.offscreen() export const blobToBase64 = (blob: any) => { return new Promise(resolve => { const reader = new FileReader() reader.onloadend = () => resolve(reader.result) reader.readAsDataURL(blob) }) } export const addMusicTitle = (canvas: any, title: any) => { canvas.getContext("2d") const water = document.createElement("canvas") // 小水印画布大小 water.width = canvas.width water.height = canvas.height + 120 const waterCtx = water.getContext("2d") as CanvasRenderingContext2D waterCtx.font = `66pt Calibri` waterCtx.fillStyle = "#000" waterCtx.textAlign = "center" waterCtx.drawImage(canvas, 0, 40) waterCtx.fillText(title, canvas.width / 2, 160) return water } let canvas = null as any export const svgtoblob = async (svg: any, width: any, height: any, name: string) => { if (!canvas) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore canvas = new OffscreenCanvas(width, height) } const ctx = canvas.getContext("2d")! let v: any = await Canvg.fromString(ctx!, svg, preset) /** * Resize SVG to fit in given size. * @param width * @param height * @param preserveAspectRatio */ v.resize(width * 2, height * 2, "xMidYMid meet") // Render only first frame, ignoring animations and mouse. await v.start() // const blob = await canvas.convertToBlob() // const base64 = await blobToBase64(blob) const base64 = await canvasAddPadding(canvas, name) ctx.clearRect(0, 0, canvas.width, canvas.height) await v.stop() v = null return base64 } const convertToBlob = (canvas: any, type = "image/png") => { return new Promise((resolve, reject) => { canvas.toBlob((blob: Blob) => { if (blob) { resolve(blob) } else { reject(new Error("转换失败")) } }, type) }) } const canvasAddPadding = async (sourceCanvas: any, name: string) => { const targetCanvas = document.createElement("canvas") targetCanvas.width = sourceCanvas.width + 400 targetCanvas.height = sourceCanvas.height + 200 // 坐标(0,0) 表示从此处开始绘制,相当于偏移。 const targetContext = targetCanvas.getContext("2d") as CanvasRenderingContext2D // const sourceContext = sourceCanvas.getContext("2d") as CanvasRenderingContext2D // 从源canvas中获取图像数据 // const imageData = sourceContext.getImageData(0, 0, sourceCanvas.width, sourceCanvas.height) // 清空目标canvas targetContext.clearRect(0, 0, targetCanvas.width, targetCanvas.height) // 将图像数据绘制到目标canvas上,并添加边距 // targetContext.putImageData(imageData, 200, 100) targetContext.fillStyle = "#fff" targetContext.fillRect(0, 0, targetCanvas.width, targetCanvas.height) // targetCanvas = await addMusicTitle(targetCanvas, name) // 小水印画布大小 // const waterCtx = water.getContext("2d") as CanvasRenderingContext2D targetContext.font = `66pt Calibri` targetContext.fillStyle = "#000" targetContext.textAlign = "center" targetContext.drawImage(canvas, 200, 240) targetContext.fillText(name, canvas.width / 2, 200) const blob = await convertToBlob(targetCanvas) // const base64 = await blobToBase64(blob) targetContext.clearRect(0, 0, targetCanvas.width, targetCanvas.height) return blob } // // 获取文件blob格式 export const imgToCanvas = async (url: string) => { const img = document.createElement("img") img.setAttribute("crossOrigin", "anonymous") // 为了处理base64 和 连接加载不同的 if (url && typeof url == "string" && url.includes("data:image")) { img.src = url } else { img.src = url + `?t=${+new Date()}` } // 防止跨域引起的 Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. await new Promise(resolve => (img.onload = resolve)) // 创建canvas DOM元素,并设置其宽高和图片一样 const canvas = document.createElement("canvas") canvas.width = img.width canvas.height = img.height // 坐标(0,0) 表示从此处开始绘制,相当于偏移。 const ctx = canvas.getContext("2d") as CanvasRenderingContext2D ctx.fillStyle = "rgb(255, 255, 255)" ctx.fillStyle = "#fff" ctx.fillRect(0, 0, img.width, img.height) ctx.drawImage(img, 0, 0) return canvas }