Upload public.js
Browse files- backend/src/routes/public.js +84 -0
backend/src/routes/public.js
CHANGED
|
@@ -1147,4 +1147,88 @@ router.get('/direct-image/:userId/:pptId/:slideIndex?', async (req, res, next) =
|
|
| 1147 |
}
|
| 1148 |
});
|
| 1149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1150 |
export default router;
|
|
|
|
| 1147 |
}
|
| 1148 |
});
|
| 1149 |
|
| 1150 |
+
// 存储前端生成的图片数据
|
| 1151 |
+
const imageCache = new Map();
|
| 1152 |
+
|
| 1153 |
+
// POST endpoint to receive frontend-generated images
|
| 1154 |
+
router.post('/save-image/:userId/:pptId/:slideIndex', express.json({ limit: '10mb' }), async (req, res, next) => {
|
| 1155 |
+
try {
|
| 1156 |
+
const { userId, pptId, slideIndex } = req.params;
|
| 1157 |
+
const { imageData, format = 'jpeg', quality = 90 } = req.body;
|
| 1158 |
+
|
| 1159 |
+
if (!imageData) {
|
| 1160 |
+
return res.status(400).json({ error: 'Image data is required' });
|
| 1161 |
+
}
|
| 1162 |
+
|
| 1163 |
+
// 生成唯一的图片ID
|
| 1164 |
+
const imageId = `${userId}-${pptId}-${slideIndex}-${Date.now()}`;
|
| 1165 |
+
|
| 1166 |
+
// 存储图片数据到内存缓存
|
| 1167 |
+
imageCache.set(imageId, {
|
| 1168 |
+
data: imageData,
|
| 1169 |
+
format,
|
| 1170 |
+
quality,
|
| 1171 |
+
userId,
|
| 1172 |
+
pptId,
|
| 1173 |
+
slideIndex,
|
| 1174 |
+
timestamp: new Date().toISOString(),
|
| 1175 |
+
contentType: `image/${format === 'jpg' ? 'jpeg' : format}`
|
| 1176 |
+
});
|
| 1177 |
+
|
| 1178 |
+
// 设置过期时间(1小时后自动清理)
|
| 1179 |
+
setTimeout(() => {
|
| 1180 |
+
imageCache.delete(imageId);
|
| 1181 |
+
}, 3600000);
|
| 1182 |
+
|
| 1183 |
+
// 返回图片访问URL
|
| 1184 |
+
const baseUrl = req.protocol + '://' + req.get('host');
|
| 1185 |
+
const imageUrl = `${baseUrl}/api/public/cached-image/${imageId}`;
|
| 1186 |
+
|
| 1187 |
+
console.log(`✅ Image saved with ID: ${imageId}`);
|
| 1188 |
+
|
| 1189 |
+
res.json({
|
| 1190 |
+
success: true,
|
| 1191 |
+
imageId,
|
| 1192 |
+
imageUrl,
|
| 1193 |
+
expiresAt: new Date(Date.now() + 3600000).toISOString()
|
| 1194 |
+
});
|
| 1195 |
+
|
| 1196 |
+
} catch (error) {
|
| 1197 |
+
console.error('❌ Failed to save image:', error);
|
| 1198 |
+
next(error);
|
| 1199 |
+
}
|
| 1200 |
+
});
|
| 1201 |
+
|
| 1202 |
+
// GET endpoint to serve cached images
|
| 1203 |
+
router.get('/cached-image/:imageId', async (req, res, next) => {
|
| 1204 |
+
try {
|
| 1205 |
+
const { imageId } = req.params;
|
| 1206 |
+
|
| 1207 |
+
const cachedImage = imageCache.get(imageId);
|
| 1208 |
+
if (!cachedImage) {
|
| 1209 |
+
return res.status(404).json({ error: 'Image not found or expired' });
|
| 1210 |
+
}
|
| 1211 |
+
|
| 1212 |
+
// 设置响应头
|
| 1213 |
+
res.setHeader('Content-Type', cachedImage.contentType);
|
| 1214 |
+
res.setHeader('Cache-Control', 'public, max-age=3600');
|
| 1215 |
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
| 1216 |
+
res.setHeader('X-Image-Source', 'frontend-generated');
|
| 1217 |
+
res.setHeader('X-Generation-Time', cachedImage.timestamp);
|
| 1218 |
+
|
| 1219 |
+
// 如果是base64数据,需要转换
|
| 1220 |
+
if (cachedImage.data.startsWith('data:')) {
|
| 1221 |
+
const base64Data = cachedImage.data.split(',')[1];
|
| 1222 |
+
const buffer = Buffer.from(base64Data, 'base64');
|
| 1223 |
+
res.send(buffer);
|
| 1224 |
+
} else {
|
| 1225 |
+
res.send(cachedImage.data);
|
| 1226 |
+
}
|
| 1227 |
+
|
| 1228 |
+
} catch (error) {
|
| 1229 |
+
console.error('❌ Failed to serve cached image:', error);
|
| 1230 |
+
next(error);
|
| 1231 |
+
}
|
| 1232 |
+
});
|
| 1233 |
+
|
| 1234 |
export default router;
|