import { saveAs } from "file-saver" import QRCode from "qrcode" interface Position { x: number y: number } export function editQRCodeImg() { const title = document.title const desc = document.head.querySelector('meta[name="author"]') ? document.head.querySelector('meta[name="description"]')! .content : "" const href = location.href const authorDom = (document.querySelector(".author-name") || document.querySelector(".article-box__meta .item")) as HTMLElement const hostname = location.hostname const author = authorDom ? authorDom.innerText : "" const encodedContent = encodeURIComponent(title) const encodedAuthor = encodeURIComponent(author) const encodedDesc = encodeURIComponent(desc) let encodedBook = null const encodedUrl = encodeURIComponent(href) hostname.includes("csdn") && (encodedBook = encodeURIComponent("《CSDN》")) hostname.includes("zhihu") && (encodedBook = encodeURIComponent("《知乎》")) hostname.includes("baidu") && (encodedBook = encodeURIComponent("《百度》")) hostname.includes("jianshu") && (encodedBook = encodeURIComponent("《简书》")) hostname.includes("jb51") && (encodedBook = encodeURIComponent("《脚本之家》")) hostname.includes("cnblogs") && (encodedBook = encodeURIComponent("《博客园》")) hostname.includes("51cto") && (encodedBook = encodeURIComponent("《51CTO》")) hostname.includes("juejin") && (encodedBook = encodeURIComponent("《掘金》")) hostname.includes("php") && (encodedBook = encodeURIComponent("《php中文网》")) hostname.includes("oschina") && (encodedBook = encodeURIComponent("《开源中国》")) hostname.includes("segmentfault") && (encodedBook = encodeURIComponent("《思否》")) hostname.includes("weixin") && (encodedBook = encodeURIComponent("《微信》")) hostname.includes("medium") && (encodedBook = encodeURIComponent("《medium》")) // 基础链接地址,这里假设为 example.com const baseUrl = "https://code-box.fun/editor-quote?" const finalUrl = `${baseUrl}content=${encodedContent}&author=${encodedAuthor}&book=${encodedBook}&url=${encodedUrl}` window.open(finalUrl) } export default function makerQRCodeImg() { const qrcodepostmaker = document.createElement("canvas") qrcodepostmaker.id = "qrcodepostmaker" qrcodepostmaker.style.display = "none" document.body.appendChild(qrcodepostmaker) // 文本换行处理 const textComputer = ( text: string, style: string, width: number, ctx: CanvasRenderingContext2D ): string[] => { if (text.replace(/\s/g, "").length === 0) { return [] } ctx.font = style let temp = 0 const row: string[] = [] for (let i = 0; i <= text.length; i++) { if (ctx.measureText(text.substring(temp, i)).width >= width) { row.push(text.substring(temp, i - 1)) temp = i - 1 } else if (i === text.length) { row.push(text.substring(temp, i)) } } return row } // 绘制文本 const textWriter = ( textArr: string[], Style: string, align: CanvasTextAlign, color: string, borderColor: string, fontSize: number, lineHeight: number, pos: Position, ctx: CanvasRenderingContext2D ): Position => { ctx.font = Style ctx.textAlign = align ctx.fillStyle = color ctx.strokeStyle = borderColor for (const text of textArr) { pos.y += fontSize * lineHeight ctx.fillText(text, pos.x, pos.y) } return pos } // 生成海报 const makerQRPost = (): void => { const canvas = document.querySelector("#qrcodepostmaker") const ctx = canvas.getContext("2d") if (!ctx) return const QRCodeData = ctx.getImageData(0, 0, canvas.width, canvas.height) const title = document.title const desc = document.head.querySelector('meta[name="description"]') ? document.head.querySelector( 'meta[name="description"]' )!.content : "" const cardWidth = 360 const lineHeight = 1.6 const margin = 36 const titleStyle = 'Bold 18px "Microsoft YaHei"' const descStyle = '16px "Microsoft YaHei"' const titleArray = textComputer( title, titleStyle, cardWidth - margin * 2, ctx ) const descArray = textComputer(desc, descStyle, cardWidth - margin * 2, ctx) const cardHeight = margin * 2.5 + 18 * titleArray.length * lineHeight + 16 * descArray.length * lineHeight + (descArray.length ? margin / 2 : 0) + 300 canvas.width = cardWidth canvas.height = cardHeight const myGradient = ctx.createLinearGradient(0, 0, 0, cardHeight) myGradient.addColorStop(0, "#2980B9") myGradient.addColorStop(0.5, "#6DD5FA") myGradient.addColorStop(1, "#FFFFFF") ctx.fillStyle = myGradient ctx.fillRect(0, 0, cardWidth, cardHeight) ctx.fillStyle = "#FFFFFF" ctx.beginPath() ctx.arc(margin * 0.4, cardHeight - margin * 5, margin, 0, Math.PI * 2, true) ctx.arc( cardWidth - margin * 0.4, cardHeight - margin * 3, margin * 0.8, 0, Math.PI * 2, true ) ctx.fillRect(0, cardHeight - margin * 5, cardWidth / 2, margin * 5) ctx.fillRect( cardWidth / 2, cardHeight - margin * 3, cardWidth / 2, margin * 3 ) ctx.fill() const titleEnd = textWriter( titleArray, titleStyle, "center", "black", "rgba(255, 255, 255, 0.6)", 18, lineHeight, { x: cardWidth / 2, y: margin }, ctx ) const descEnd = textWriter( descArray, descStyle, "left", "black", "rgba(255, 255, 255, 0.6)", 16, lineHeight, { x: margin, y: titleEnd.y + margin / 2 }, ctx ) ctx.fillStyle = "white" ctx.fillRect((cardWidth - 288) / 2, descEnd.y + margin - 24, 288, 288) ctx.putImageData(QRCodeData, (cardWidth - 256) / 2, descEnd.y + margin) textWriter( ["(长按识别二维码进行访问)"], descStyle, "center", "rgba(0, 0, 0, 0.6)", "rgba(255, 255, 255, 0.6)", 16, lineHeight, { x: cardWidth / 2, y: descEnd.y + margin + 256 }, ctx ) textWriter( ["codebox-一键复制代码/下载文章"], descStyle, "center", "rgba(0, 0, 0, 0.6)", "rgba(255, 255, 255, 0.6)", 16, lineHeight, { x: cardWidth / 2, y: descEnd.y + margin + 280 }, ctx ) saveAs(canvas.toDataURL("image/png"), title + ".png") qrcodepostmaker.parentNode?.removeChild(qrcodepostmaker) } let tryTimes = 30 const makeQRCode = window.setInterval(() => { try { QRCode.toCanvas( document.getElementById("qrcodepostmaker"), window.location.href, { width: 260, errorCorrectionLevel: "Q" }, (error) => { if (error) { console.log(error) return } makerQRPost() } ) window.clearInterval(makeQRCode) } catch (error) { console.log(error) tryTimes-- if (!tryTimes) { window.clearInterval(makeQRCode) alert("没能成功载入功能库,请刷新重试~") } } }, 200) }