123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- 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
- }
|