fix: 修改dockerfile,更新json文件
This commit is contained in:
parent
0deaced829
commit
1aed3a8490
12
Dockerfile
12
Dockerfile
@ -1,20 +1,20 @@
|
|||||||
# 使用官方的 Node.js 镜像作为基础镜像
|
# 使用官方Node.js镜像作为基础镜像
|
||||||
FROM node:18
|
FROM node:18-alpine
|
||||||
|
|
||||||
# 设置工作目录
|
# 设置工作目录
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# 复制 package.json 和 package-lock.json(如果有)到工作目录
|
# 复制package.json和package-lock.json
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
# 复制项目的源代码到工作目录
|
# 复制项目文件
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# 暴露服务端口
|
# 暴露服务端口
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
# 启动应用程序
|
# 启动服务
|
||||||
CMD ["npm", "start"]
|
CMD ["node", "index.js"]
|
||||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -8,9 +8,9 @@
|
|||||||
"name": "image-generator-service",
|
"name": "image-generator-service",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"canvas": "^2.9.0",
|
"canvas": "^2.11.2",
|
||||||
"express": "^4.17.1",
|
"express": "^4.19.2",
|
||||||
"qrcode": "^1.4.4"
|
"qrcode": "^1.5.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mapbox/node-pre-gyp": {
|
"node_modules/@mapbox/node-pre-gyp": {
|
||||||
|
@ -6,9 +6,8 @@
|
|||||||
"start": "node src/index.js"
|
"start": "node src/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"canvas": "^2.9.0",
|
"canvas": "^2.11.2",
|
||||||
"express": "^4.17.1",
|
"express": "^4.19.2",
|
||||||
"qrcode": "^1.4.4"
|
"qrcode": "^1.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
104
src/index.js
104
src/index.js
@ -1,21 +1,50 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { createCanvas, loadImage } = require('canvas');
|
const { createCanvas, loadImage } = require('canvas');
|
||||||
const QRCode = require('qrcode');
|
const QRCode = require('qrcode');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
async function generateImage(title, tags, qrData) {
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
app.post('/generateImage', async (req, res) => {
|
||||||
|
const { title, tags, qrData } = req.body;
|
||||||
const canvas = createCanvas(378, 613);
|
const canvas = createCanvas(378, 613);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// 主图
|
||||||
const mainPath = 'https://tachybase-1321007335.cos.ap-shanghai.myqcloud.com/f17e5a563df5dbd37a96913af892608f.png';
|
const mainPath = 'https://tachybase-1321007335.cos.ap-shanghai.myqcloud.com/f17e5a563df5dbd37a96913af892608f.png';
|
||||||
const mainImage = await loadImage(mainPath);
|
const mainImage = await loadImage(mainPath);
|
||||||
ctx.drawImage(mainImage, 0, 0, canvas.width, canvas.height / 2 + 80);
|
ctx.drawImage(mainImage, 0, 0, canvas.width, canvas.height / 2 + 80);
|
||||||
|
|
||||||
|
// 白色区域
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = '#ffffff';
|
||||||
ctx.fillRect(0, 387, canvas.width, canvas.height);
|
ctx.fillRect(0, 387, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
// 标题
|
||||||
ctx.fillStyle = '#000000';
|
ctx.fillStyle = '#000000';
|
||||||
ctx.font = '600 22px Arial';
|
ctx.font = '600 22px Arial';
|
||||||
ctx.fillText(title, 20, canvas.height / 2 + 116);
|
ctx.fillText(title, 20, canvas.height / 2 + 116);
|
||||||
|
|
||||||
|
// 标签背景
|
||||||
ctx.fillStyle = '#f0f0f0';
|
ctx.fillStyle = '#f0f0f0';
|
||||||
tags.forEach((tag, index) => {
|
tags.forEach((tag, index) => {
|
||||||
const cornerSize = 12;
|
const cornerSize = 12;
|
||||||
@ -27,83 +56,58 @@ async function generateImage(title, tags, qrData) {
|
|||||||
const height = 26;
|
const height = 26;
|
||||||
getBackground(ctx, x, y, cornerSize, width, height);
|
getBackground(ctx, x, y, cornerSize, width, height);
|
||||||
});
|
});
|
||||||
['1'].forEach((value) => {
|
|
||||||
|
// 二维码背景
|
||||||
const codeWidth = 135;
|
const codeWidth = 135;
|
||||||
const codeHeight = 154;
|
const codeHeight = 154;
|
||||||
const codeCornerSize = 12;
|
const codeCornerSize = 12;
|
||||||
const codeX = 229;
|
const codeX = 229;
|
||||||
const codeY = 440;
|
const codeY = 440;
|
||||||
getBackground(ctx, codeX, codeY, codeCornerSize, codeWidth, codeHeight);
|
getBackground(ctx, codeX, codeY, codeCornerSize, codeWidth, codeHeight);
|
||||||
});
|
|
||||||
|
// 标签文字
|
||||||
ctx.font = '17px Arial';
|
ctx.font = '17px Arial';
|
||||||
ctx.fillStyle = '#5e5e5e';
|
ctx.fillStyle = '#5e5e5e';
|
||||||
tags.forEach((tag, index) => {
|
tags.forEach((tag, index) => {
|
||||||
const textMeta = ctx.measureText(tag);
|
const textMeta = ctx.measureText(tag);
|
||||||
const tagContent = {
|
let tagContent = tag;
|
||||||
width: textMeta.width + 55,
|
|
||||||
tag,
|
|
||||||
};
|
|
||||||
const maxWidth = 173;
|
const maxWidth = 173;
|
||||||
for (let i = 0; i <= 300; i++) {
|
|
||||||
if (tagContent.width < maxWidth) {
|
if (textMeta.width > maxWidth) {
|
||||||
break;
|
for (let i = tag.length; i > 0; i--) {
|
||||||
} else {
|
tagContent = tag.slice(0, i) + '...';
|
||||||
const text = tagContent.tag.split('').slice(0, -1).join('');
|
if (ctx.measureText(tagContent).width < maxWidth) {
|
||||||
tagContent.tag = text;
|
|
||||||
const tagText = ctx.measureText(text + '...');
|
|
||||||
if (tagText.width < maxWidth) {
|
|
||||||
tagContent.tag = text + '...';
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.fillText(tagContent.tag, 48, 469 + index * 39);
|
|
||||||
|
ctx.fillText(tagContent, 48, 469 + index * 39);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 标签图标
|
||||||
const icon = 'https://tachybase-1321007335.cos.ap-shanghai.myqcloud.com/c24fc8982d4a469e63f70538d96ead23.png';
|
const icon = 'https://tachybase-1321007335.cos.ap-shanghai.myqcloud.com/c24fc8982d4a469e63f70538d96ead23.png';
|
||||||
const iconImage = await loadImage(icon);
|
const iconImage = await loadImage(icon);
|
||||||
tags.forEach((tag, index) => {
|
tags.forEach((tag, index) => {
|
||||||
ctx.drawImage(iconImage, 26, 452 + index * 39, 17, 20);
|
ctx.drawImage(iconImage, 26, 452 + index * 39, 17, 20);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 二维码
|
||||||
const qrCodeCanvas = createCanvas(100, 100);
|
const qrCodeCanvas = createCanvas(100, 100);
|
||||||
await QRCode.toCanvas(qrCodeCanvas, qrData);
|
await QRCode.toCanvas(qrCodeCanvas, qrData);
|
||||||
const qrCodeImage = qrCodeCanvas;
|
const qrCodeImage = qrCodeCanvas;
|
||||||
const qrCodeX = canvas.width - 139;
|
ctx.drawImage(qrCodeImage, canvas.width - 139, 448, 116, 115);
|
||||||
const qrCodeY = 448;
|
|
||||||
ctx.drawImage(qrCodeImage, qrCodeX, qrCodeY, 116, 115);
|
// 二维码文字
|
||||||
ctx.fillStyle = '#9d9d9d';
|
ctx.fillStyle = '#9d9d9d';
|
||||||
ctx.fillText('长按识别', 261, 585);
|
ctx.fillText('长按识别', 261, 585);
|
||||||
|
|
||||||
return canvas.toDataURL('image/png');
|
// 返回DataURL
|
||||||
}
|
const dataURL = 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 });
|
res.json({ dataURL });
|
||||||
} catch (error) {
|
|
||||||
res.status(500).send('Error generating image');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const getBackground = (ctx, x, y, cornerSize, width, height) => {
|
const port = 3000;
|
||||||
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, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Server is running on port ${port}`);
|
console.log(`Server running on port ${port}`);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user