commit 058bb3ba7780b127a80f312a4c6b7e602dc0c3c9 Author: huan <1486343814@qq.com> Date: Thu Aug 8 13:29:13 2024 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..08ff5fb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:18-alpine + +WORKDIR /app + +COPY package*.json ./ +RUN npm install + +COPY . . + +EXPOSE 3000 + +CMD ["npm", "start"] diff --git a/package.json b/package.json new file mode 100644 index 0000000..0c993a7 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "image-generator-service", + "version": "1.0.0", + "main": "src/index.js", + "scripts": { + "start": "node src/index.js" + }, + "dependencies": { + "canvas": "^2.9.0", + "express": "^4.17.1", + "qrcode": "^1.4.4" + } + } + \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..030c18a --- /dev/null +++ b/src/index.js @@ -0,0 +1,109 @@ +const express = require('express'); +const { createCanvas, loadImage } = require('canvas'); +const QRCode = require('qrcode'); + +const app = express(); +app.use(express.json()); + +async function generateImage(title, tags, qrData) { + const canvas = createCanvas(378, 613); + const ctx = canvas.getContext('2d'); + const mainPath = 'https://tachybase-1321007335.cos.ap-shanghai.myqcloud.com/f17e5a563df5dbd37a96913af892608f.png'; + const mainImage = await loadImage(mainPath); + ctx.drawImage(mainImage, 0, 0, canvas.width, canvas.height / 2 + 80); + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 387, canvas.width, canvas.height); + ctx.fillStyle = '#000000'; + ctx.font = '600 22px Arial'; + ctx.fillText(title, 20, canvas.height / 2 + 116); + ctx.fillStyle = '#f0f0f0'; + tags.forEach((tag, index) => { + const cornerSize = 12; + const x = 20; + const y = 450 + index * 39; + ctx.font = '17px Arial'; + const textMeta = ctx.measureText(tag); + const width = textMeta.width + 35 > 202 ? 202 : textMeta.width + 35; + const height = 26; + getBackground(ctx, x, y, cornerSize, width, height); + }); + ['1'].forEach(value => { + const codeWidth = 135; + const codeHeight = 154; + const codeCornerSize = 12; + const codeX = 229; + const codeY = 440; + getBackground(ctx, codeX, codeY, codeCornerSize, codeWidth, codeHeight); + }); + ctx.font = '17px Arial'; + ctx.fillStyle = '#5e5e5e'; + tags.forEach((tag, index) => { + const textMeta = ctx.measureText(tag); + const tagContent = { + width: textMeta.width + 55, + tag + }; + const maxWidth = 173; + for (let i = 0; i <= 300; i++) { + if (tagContent.width < maxWidth) { + break; + } else { + const text = tagContent.tag.split('').slice(0, -1).join(''); + tagContent.tag = text; + const tagText = ctx.measureText(text + '...'); + if (tagText.width < maxWidth) { + tagContent.tag = text + '...'; + break; + } + } + } + ctx.fillText(tagContent.tag, 48, 469 + index * 39); + }); + const icon = 'https://tachybase-1321007335.cos.ap-shanghai.myqcloud.com/c24fc8982d4a469e63f70538d96ead23.png'; + const iconImage = await loadImage(icon); + tags.forEach((tag, index) => { + ctx.drawImage(iconImage, 26, 452 + index * 39, 17, 20); + }); + const qrCodeCanvas = createCanvas(100, 100); + await QRCode.toCanvas(qrCodeCanvas, qrData); + const qrCodeImage = qrCodeCanvas; + const qrCodeX = canvas.width - 139; + const qrCodeY = 448; + ctx.drawImage(qrCodeImage, qrCodeX, qrCodeY, 116, 115); + ctx.fillStyle = '#9d9d9d'; + ctx.fillText('长按识别', 261, 585); + + return canvas.toDataURL('image/png'); +} + +app.post('/generate-image', async (req, res) => { + const { title, tags, qrData } = req.body; + try { + const dataURL = await generateImage(title, tags, qrData); + res.json({ dataURL }); + } catch (error) { + res.status(500).send('Error generating image'); + } +}); + +const getBackground = (ctx, x, y, cornerSize, width, height) => { + ctx.lineJoin = 'round'; + ctx.lineWidth = 0.5; + ctx.moveTo(x + cornerSize, y); + ctx.arcTo(x + width, y, x + width, y + cornerSize, cornerSize); + ctx.lineTo(x + width, y + height - cornerSize); + ctx.arcTo(x + width, y + height, x + width - cornerSize, y + height, cornerSize); + ctx.lineTo(x + cornerSize, y + height); + ctx.arcTo(x, y + height, x, y + height - cornerSize, cornerSize); + ctx.lineTo(x, y + cornerSize); + ctx.arcTo(x, y, x + cornerSize, y, cornerSize); + ctx.closePath(); + ctx.strokeStyle = '#f0f0f0'; + ctx.fill(); + ctx.stroke(); +}; + +const port = process.env.PORT || 3000; +app.listen(port, () => { + console.log(`Server is running on port ${port}`); +});