Files
code-box/utils/makerQRPost.ts
2025-03-12 13:54:24 +08:00

251 lines
7.2 KiB
TypeScript

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<HTMLMetaElement>('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<HTMLCanvasElement>("#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<HTMLMetaElement>(
'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)
}