|
|
@@ -69,20 +69,6 @@ public class NumberController {
|
|
|
gameEventService.exportNumberTable(request, response, eventId);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- /**
|
|
|
- * 生成号码布
|
|
|
- *
|
|
|
- */
|
|
|
- @SaCheckPermission("system:gameEvent:numberBib")
|
|
|
- @PostMapping("/generateBib")
|
|
|
- public void generateNumberBib(HttpServletResponse response,
|
|
|
- @RequestPart("bgImage") MultipartFile bgImage,
|
|
|
- @RequestPart(name = "logo", required = false) MultipartFile logo,
|
|
|
- GenerateBibBo bibParam) {
|
|
|
- gameEventService.generateNumberBib(response, bgImage, logo, bibParam);
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 创建参赛证生成任务(异步)
|
|
|
*/
|
|
|
@@ -105,7 +91,7 @@ public class NumberController {
|
|
|
bibParam.getLogoX(), bibParam.getLogoY());
|
|
|
log.info("二维码坐标详情 - qRCodeX: {}, qRCodeY: {}",
|
|
|
bibParam.getQRCodeX(), bibParam.getQRCodeY());
|
|
|
- log.info("Logo缩放: {}, 二维码缩放: {}", bibParam.getLogoScale(), bibParam.getBarcodeScale());
|
|
|
+ // log.info("Logo缩放: {}, 二维码缩放: {}", bibParam.getLogoScale(), bibParam.getBarcodeScale());
|
|
|
|
|
|
// 先保存图片文件,再创建任务
|
|
|
final String bgImagePath = gameBibTaskService.saveImageFile(bgImage, "bg_" + System.currentTimeMillis());
|
|
|
@@ -189,11 +175,11 @@ public class NumberController {
|
|
|
if (task == null) {
|
|
|
return R.fail("任务不存在");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (task.getOssId() == null) {
|
|
|
return R.fail("任务文件未上传到OSS");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 生成1小时有效的预签名URL
|
|
|
log.info("开始生成预签名URL,taskId: {}, ossId: {}", taskId, task.getOssId());
|
|
|
String presignedUrl = sysOssService.generatePresignedUrl(task.getOssId(), 3600);
|
|
|
@@ -209,110 +195,42 @@ public class NumberController {
|
|
|
* 验证和修正参赛证参数边界
|
|
|
*/
|
|
|
private void validateAndCorrectBibParams(GenerateBibBo bibParam) {
|
|
|
- // 统一使用百分比坐标系统 (0-100)
|
|
|
- final double maxPercent = 100.0;
|
|
|
- final double minPercent = 0.0;
|
|
|
-
|
|
|
- // 修正Logo位置(百分比)
|
|
|
- if (bibParam.getLogoX() != null) {
|
|
|
- double logoX = Math.max(minPercent, Math.min(maxPercent, bibParam.getLogoX()));
|
|
|
- if (Double.compare(logoX, bibParam.getLogoX()) != 0) {
|
|
|
- log.warn("Logo X坐标百分比超出边界,从 {} 修正为 {}", bibParam.getLogoX(), logoX);
|
|
|
- bibParam.setLogoX(logoX);
|
|
|
+ // 修正二维码尺寸(范围16-512)
|
|
|
+ if (bibParam.getQRCodeWidth() != null) {
|
|
|
+ int qrWidth = Math.max(16, Math.min(512, bibParam.getQRCodeWidth()));
|
|
|
+ if (Integer.compare(qrWidth, bibParam.getQRCodeWidth()) != 0) {
|
|
|
+ log.warn("二维码宽度超出边界,从 {} 修正为 {}", bibParam.getQRCodeWidth(), qrWidth);
|
|
|
+ bibParam.setQRCodeWidth(qrWidth);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (bibParam.getLogoY() != null) {
|
|
|
- double logoY = Math.max(minPercent, Math.min(maxPercent, bibParam.getLogoY()));
|
|
|
- if (Double.compare(logoY, bibParam.getLogoY()) != 0) {
|
|
|
- log.warn("Logo Y坐标百分比超出边界,从 {} 修正为 {}", bibParam.getLogoY(), logoY);
|
|
|
- bibParam.setLogoY(logoY);
|
|
|
+ if (bibParam.getQRCodeHeight() != null) {
|
|
|
+ int qrHeight = Math.max(16, Math.min(512, bibParam.getQRCodeHeight()));
|
|
|
+ if (Integer.compare(qrHeight, bibParam.getQRCodeHeight()) != 0) {
|
|
|
+ log.warn("二维码高度超出边界,从 {} 修正为 {}", bibParam.getQRCodeHeight(), qrHeight);
|
|
|
+ bibParam.setQRCodeHeight(qrHeight);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 修正二维码位置(百分比)
|
|
|
- if (bibParam.getQRCodeX() != null) {
|
|
|
- double qrX = Math.max(minPercent, Math.min(maxPercent, bibParam.getQRCodeX()));
|
|
|
- if (Double.compare(qrX, bibParam.getQRCodeX()) != 0) {
|
|
|
- log.warn("二维码 X坐标百分比超出边界,从 {} 修正为 {}", bibParam.getQRCodeX(), qrX);
|
|
|
- bibParam.setQRCodeX(qrX);
|
|
|
+ // 修正号码字体大小(范围8-200)
|
|
|
+ if (bibParam.getNumberFontSize() != null) {
|
|
|
+ int numberFontSize = Math.max(8, Math.min(200, bibParam.getNumberFontSize()));
|
|
|
+ if (Integer.compare(numberFontSize, bibParam.getNumberFontSize()) != 0) {
|
|
|
+ log.warn("号码字体大小超出边界,从 {} 修正为 {}", bibParam.getNumberFontSize(), numberFontSize);
|
|
|
+ bibParam.setNumberFontSize(numberFontSize);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (bibParam.getQRCodeY() != null) {
|
|
|
- double qrY = Math.max(minPercent, Math.min(maxPercent, bibParam.getQRCodeY()));
|
|
|
- if (Double.compare(qrY, bibParam.getQRCodeY()) != 0) {
|
|
|
- log.warn("二维码 Y坐标百分比超出边界,从 {} 修正为 {}", bibParam.getQRCodeY(), qrY);
|
|
|
- bibParam.setQRCodeY(qrY);
|
|
|
+ // 修正赛事名称字体大小(范围8-120)
|
|
|
+ if (bibParam.getEventFontSize() != null) {
|
|
|
+ int eventFontSize = Math.max(8, Math.min(120, bibParam.getEventFontSize()));
|
|
|
+ if (Integer.compare(eventFontSize, bibParam.getEventFontSize()) != 0) {
|
|
|
+ log.warn("赛事名称字体大小超出边界,从 {} 修正为 {}", bibParam.getEventFontSize(), eventFontSize);
|
|
|
+ bibParam.setEventFontSize(eventFontSize);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 修正号码位置(百分比值,范围0-100)
|
|
|
- if (bibParam.getNumberX() != null) {
|
|
|
- double numberX = Math.max(0.0, Math.min(100.0, bibParam.getNumberX()));
|
|
|
- if (Double.compare(numberX, bibParam.getNumberX()) != 0) {
|
|
|
- log.warn("号码 X坐标百分比超出边界,从 {} 修正为 {}", bibParam.getNumberX(), numberX);
|
|
|
- bibParam.setNumberX(numberX);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (bibParam.getNumberY() != null) {
|
|
|
- double numberY = Math.max(0.0, Math.min(100.0, bibParam.getNumberY()));
|
|
|
- if (Double.compare(numberY, bibParam.getNumberY()) != 0) {
|
|
|
- log.warn("号码 Y坐标百分比超出边界,从 {} 修正为 {}", bibParam.getNumberY(), numberY);
|
|
|
- bibParam.setNumberY(numberY);
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- // 修正赛事名称位置(百分比值,范围0-100)
|
|
|
- if (bibParam.getEventX() != null) {
|
|
|
- double eventX = Math.max(0.0, Math.min(100.0, bibParam.getEventX()));
|
|
|
- if (Double.compare(eventX, bibParam.getEventX()) != 0) {
|
|
|
- log.warn("赛事名称 X坐标百分比超出边界,从 {} 修正为 {}", bibParam.getEventX(), eventX);
|
|
|
- bibParam.setEventX(eventX);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (bibParam.getEventY() != null) {
|
|
|
- double eventY = Math.max(0.0, Math.min(100.0, bibParam.getEventY()));
|
|
|
- if (Double.compare(eventY, bibParam.getEventY()) != 0) {
|
|
|
- log.warn("赛事名称 Y坐标百分比超出边界,从 {} 修正为 {}", bibParam.getEventY(), eventY);
|
|
|
- bibParam.setEventY(eventY);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 修正缩放参数(范围0.1-5.0)
|
|
|
- if (bibParam.getLogoScale() != null) {
|
|
|
- double logoScale = Math.max(0.1, Math.min(5.0, bibParam.getLogoScale()));
|
|
|
- if (Double.compare(logoScale, bibParam.getLogoScale()) != 0) {
|
|
|
- log.warn("Logo缩放参数超出边界,从 {} 修正为 {}", bibParam.getLogoScale(), logoScale);
|
|
|
- bibParam.setLogoScale(logoScale);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (bibParam.getBarcodeScale() != null) {
|
|
|
- double barcodeScale = Math.max(0.1, Math.min(5.0, bibParam.getBarcodeScale()));
|
|
|
- if (Double.compare(barcodeScale, bibParam.getBarcodeScale()) != 0) {
|
|
|
- log.warn("二维码缩放参数超出边界,从 {} 修正为 {}", bibParam.getBarcodeScale(), barcodeScale);
|
|
|
- bibParam.setBarcodeScale(barcodeScale);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (bibParam.getNumberScale() != null) {
|
|
|
- double numberScale = Math.max(0.1, Math.min(5.0, bibParam.getNumberScale()));
|
|
|
- if (Double.compare(numberScale, bibParam.getNumberScale()) != 0) {
|
|
|
- log.warn("号码缩放参数超出边界,从 {} 修正为 {}", bibParam.getNumberScale(), numberScale);
|
|
|
- bibParam.setNumberScale(numberScale);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (bibParam.getEventScale() != null) {
|
|
|
- double eventScale = Math.max(0.1, Math.min(5.0, bibParam.getEventScale()));
|
|
|
- if (Double.compare(eventScale, bibParam.getEventScale()) != 0) {
|
|
|
- log.warn("赛事名称缩放参数超出边界,从 {} 修正为 {}", bibParam.getEventScale(), eventScale);
|
|
|
- bibParam.setEventScale(eventScale);
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
// 修正字体大小(范围8-200)
|
|
|
if (bibParam.getFontSize() != null) {
|
|
|
@@ -372,7 +290,7 @@ public class NumberController {
|
|
|
// 获取目标画布尺寸
|
|
|
int targetWidth = bibParam.getCanvasWidth() != null ? bibParam.getCanvasWidth() : originalBgImage.getWidth();
|
|
|
int targetHeight = bibParam.getCanvasHeight() != null ? bibParam.getCanvasHeight() : originalBgImage.getHeight();
|
|
|
-
|
|
|
+
|
|
|
// 创建目标尺寸的画布
|
|
|
BufferedImage bgImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
|
|
|
Graphics2D g2d = bgImage.createGraphics();
|
|
|
@@ -383,7 +301,7 @@ public class NumberController {
|
|
|
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
|
|
|
|
// 将原始背景图片拉伸/缩放到目标画布尺寸
|
|
|
- g2d.drawImage(originalBgImage, 0, 0, targetWidth, targetHeight, null);
|
|
|
+ // g2d.drawImage(originalBgImage, 0, 0, targetWidth, targetHeight, null);
|
|
|
log.info("背景图片已调整到目标尺寸: {}x{}", targetWidth, targetHeight);
|
|
|
|
|
|
// 绘制Logo(如果存在)
|
|
|
@@ -443,19 +361,20 @@ public class NumberController {
|
|
|
}
|
|
|
|
|
|
// 使用传入的Logo尺寸(前端已计算好最终尺寸)
|
|
|
- int scaledWidth, scaledHeight;
|
|
|
+ int scaledWidth = 80, scaledHeight = 80;
|
|
|
if (bibParam.getLogoWidth() != null && bibParam.getLogoHeight() != null) {
|
|
|
// 使用前端传入的Logo尺寸(已包含所有缩放计算)
|
|
|
scaledWidth = bibParam.getLogoWidth();
|
|
|
scaledHeight = bibParam.getLogoHeight();
|
|
|
log.info("使用前端计算的Logo尺寸: {}x{}", scaledWidth, scaledHeight);
|
|
|
- } else {
|
|
|
- // 回退到原始缩放逻辑(兼容旧版本)
|
|
|
- Double logoScale = bibParam.getLogoScale() != null ? bibParam.getLogoScale() : 1.0;
|
|
|
- scaledWidth = (int) (logoImage.getWidth() * logoScale);
|
|
|
- scaledHeight = (int) (logoImage.getHeight() * logoScale);
|
|
|
- log.warn("使用回退缩放逻辑,Logo尺寸: {}x{}", scaledWidth, scaledHeight);
|
|
|
}
|
|
|
+ // else {
|
|
|
+ // // 回退到原始缩放逻辑(兼容旧版本)
|
|
|
+ // Double logoScale = bibParam.getLogoScale() != null ? bibParam.getLogoScale() : 1.0;
|
|
|
+ // scaledWidth = (int) (logoImage.getWidth() * logoScale);
|
|
|
+ // scaledHeight = (int) (logoImage.getHeight() * logoScale);
|
|
|
+ // log.warn("使用回退缩放逻辑,Logo尺寸: {}x{}", scaledWidth, scaledHeight);
|
|
|
+ // }
|
|
|
|
|
|
// 边界检查,确保Logo不会超出图片范围
|
|
|
if (x < 0) x = 0;
|
|
|
@@ -478,31 +397,30 @@ public class NumberController {
|
|
|
*/
|
|
|
private void drawEventNameOnTemplate(Graphics2D g2d, String eventName, GenerateBibBo bibParam, int canvasWidth, int canvasHeight) {
|
|
|
try {
|
|
|
- // 计算赛事名称位置(基于百分比)
|
|
|
- int x = (int) (canvasWidth * bibParam.getEventX() / 100);
|
|
|
- int y = (int) (canvasHeight * bibParam.getEventY() / 100);
|
|
|
+ // 使用前端传递的像素坐标
|
|
|
+ int x = bibParam.getEventX() != null ? bibParam.getEventX().intValue() : canvasWidth / 2;
|
|
|
+ int y = bibParam.getEventY() != null ? bibParam.getEventY().intValue() : canvasHeight / 4;
|
|
|
|
|
|
- // 设置字体(直接使用用户设置的字体大小和缩放)
|
|
|
- int baseFontSize = bibParam.getFontSize() != null ? bibParam.getFontSize() : 28;
|
|
|
- Double eventScale = bibParam.getEventScale() != null ? bibParam.getEventScale() : 1.0;
|
|
|
- int fontSize = (int) (baseFontSize * eventScale);
|
|
|
+ // 使用前端传递的字体大小
|
|
|
+ int fontSize = bibParam.getEventFontSize() != null ? bibParam.getEventFontSize() : 28;
|
|
|
|
|
|
- Font font = new Font(bibParam.getFontName(), Font.BOLD, fontSize);
|
|
|
+ // 使用固定字体 "黑体" 与前端保持一致
|
|
|
+ Font font = new Font("黑体", Font.BOLD, fontSize);
|
|
|
g2d.setFont(font);
|
|
|
|
|
|
- // 设置颜色
|
|
|
- Color color = new Color(bibParam.getFontColor());
|
|
|
+ // 设置颜色 - 与前端保持一致(固定黑色)
|
|
|
+ Color color = Color.BLACK;
|
|
|
g2d.setColor(color);
|
|
|
|
|
|
// 绘制赛事名称
|
|
|
FontMetrics fm = g2d.getFontMetrics();
|
|
|
int textWidth = fm.stringWidth(eventName);
|
|
|
- int textHeight = fm.getHeight();
|
|
|
+ int textAscent = fm.getAscent();
|
|
|
|
|
|
- // 居中绘制
|
|
|
- g2d.drawString(eventName, x - textWidth / 2, y + textHeight / 4);
|
|
|
- log.info("赛事名称绘制完成 - 位置: ({}, {}), 基础字体: {}, 用户缩放: {}, 最终字体: {}, 画布尺寸: {}x{}",
|
|
|
- x, y, baseFontSize, eventScale, fontSize, canvasWidth, canvasHeight);
|
|
|
+ // 居中绘制 - 与前端 transform: translateX(-50%) 和 transformOrigin: 'top center' 保持一致
|
|
|
+ g2d.drawString(eventName, x - textWidth / 2, y + textAscent);
|
|
|
+ log.info("赛事名称绘制完成 - 位置: ({}, {}), 字体大小: {}, 画布尺寸: {}x{}",
|
|
|
+ x, y, fontSize, canvasWidth, canvasHeight);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
log.error("绘制赛事名称失败", e);
|