feat: 代表团凭证展示优化
This commit is contained in:
+112
-19
@@ -52,6 +52,7 @@ import java.util.Map;
|
||||
public class TeacherCongressDelegateCardController {
|
||||
|
||||
private static final String CARD_BACK_IMG_CONFIG = "TeacherCongressCardBackImg";
|
||||
private static final String APP_LOGO_CONFIG = "AppLogo";
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@@ -61,9 +62,10 @@ public class TeacherCongressDelegateCardController {
|
||||
private SysRoleService sysRoleService;
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/teachercongress/delegate/card/index.html")
|
||||
@Ok("void")
|
||||
@SaCheckLogin
|
||||
public void h5Index() {
|
||||
public void h5Index(HttpServletResponse response) throws IOException, WriterException {
|
||||
showCard(response);
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -89,40 +91,68 @@ public class TeacherCongressDelegateCardController {
|
||||
BufferedImage resultImage = new BufferedImage(backgroundImage.getWidth(), backgroundImage.getHeight(), BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D graphics = resultImage.createGraphics();
|
||||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
graphics.drawImage(backgroundImage, 0, 0, null);
|
||||
|
||||
Map<EncodeHintType, ErrorCorrectionLevel> hintMap = new EnumMap<>(EncodeHintType.class);
|
||||
BufferedImage logoImage = tintLogo(readConfigImage(APP_LOGO_CONFIG, "系统Logo读取失败"), Color.decode("#1476DF"));
|
||||
int logoMaxWidth = resultImage.getWidth() * 55 / 100;
|
||||
int logoMaxHeight = resultImage.getHeight() * 11 / 100;
|
||||
double logoScale = Math.min((double) logoMaxWidth / logoImage.getWidth(), (double) logoMaxHeight / logoImage.getHeight());
|
||||
int logoWidth = (int) (logoImage.getWidth() * logoScale);
|
||||
int logoHeight = (int) (logoImage.getHeight() * logoScale);
|
||||
int logoX = (resultImage.getWidth() - logoWidth) / 2;
|
||||
int logoY = resultImage.getHeight() * 15 / 100;
|
||||
graphics.drawImage(logoImage, logoX, logoY, logoWidth, logoHeight, null);
|
||||
|
||||
String title = StrUtil.blankToDefault(cardInfo.getString("title"), "");
|
||||
int titleY = resultImage.getHeight() * 32 / 100;
|
||||
Font titleFont = fitFontToWidth(graphics, new Font("微软雅黑", Font.BOLD, 70), title,
|
||||
resultImage.getWidth() * 82 / 100, 36);
|
||||
commonSpacedFont(resultImage, graphics, title, titleY, titleFont, Color.decode("#1476DF"), 6);
|
||||
|
||||
Map<EncodeHintType, Object> hintMap = new EnumMap<>(EncodeHintType.class);
|
||||
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
|
||||
hintMap.put(EncodeHintType.MARGIN, 0);
|
||||
NutMap qrData = new NutMap();
|
||||
qrData.setv("userId", SecurityUtil.getUserId());
|
||||
BitMatrix bitMatrix = new MultiFormatWriter().encode(Json.toJson(qrData), BarcodeFormat.QR_CODE, 200, 200, hintMap);
|
||||
int qrCodeX = (resultImage.getWidth() - 200) / 2;
|
||||
int qrCodeY = (resultImage.getHeight() - 200) / 2;
|
||||
for (int x = 0; x < 200; x++) {
|
||||
for (int y = 0; y < 200; y++) {
|
||||
int qrCodeSize = Math.min(330, resultImage.getWidth() * 31 / 100);
|
||||
BitMatrix bitMatrix = new MultiFormatWriter().encode(Json.toJson(qrData), BarcodeFormat.QR_CODE,
|
||||
qrCodeSize, qrCodeSize, hintMap);
|
||||
int qrCodeX = (resultImage.getWidth() - qrCodeSize) / 2;
|
||||
int qrCodeY = resultImage.getHeight() * 37 / 100;
|
||||
int qrPanelPadding = 8;
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.fillRoundRect(qrCodeX - qrPanelPadding, qrCodeY - qrPanelPadding,
|
||||
qrCodeSize + qrPanelPadding * 2, qrCodeSize + qrPanelPadding * 2, 22, 22);
|
||||
for (int x = 0; x < qrCodeSize; x++) {
|
||||
for (int y = 0; y < qrCodeSize; y++) {
|
||||
if (bitMatrix.get(x, y)) {
|
||||
resultImage.setRGB(qrCodeX + x, qrCodeY + y, Color.BLACK.getRGB());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String title = StrUtil.blankToDefault(cardInfo.getString("title"), "");
|
||||
int titleY = (resultImage.getHeight() / 2) - 130;
|
||||
Font titleFont = new Font("微软雅黑", Font.PLAIN, 26).deriveFont(Font.BOLD);
|
||||
commonFont(resultImage, graphics, title, titleY, titleFont, Color.decode("#d1b930"));
|
||||
int dividerY = qrCodeY + qrCodeSize + 60;
|
||||
int dividerWidth = resultImage.getWidth() * 38 / 100;
|
||||
graphics.setColor(Color.decode("#1476DF"));
|
||||
graphics.fillRect((resultImage.getWidth() - dividerWidth) / 2, dividerY, dividerWidth, 2);
|
||||
graphics.fillRect(resultImage.getWidth() / 2 - 5, dividerY - 4, 10, 10);
|
||||
|
||||
String nameText = StrUtil.blankToDefault(cardInfo.getString("nameText"), SecurityUtil.getUserUsername());
|
||||
int nameTextY = (resultImage.getHeight() / 2) + 150;
|
||||
Font nameFont = new Font("楷体", Font.BOLD, 40);
|
||||
commonFont(resultImage, graphics, nameText, nameTextY, nameFont, Color.WHITE);
|
||||
int nameTextY = dividerY + 115;
|
||||
Font nameFont = fitFontToWidth(graphics, new Font("微软雅黑", Font.BOLD, 68), nameText,
|
||||
resultImage.getWidth() * 70 / 100, 34);
|
||||
commonSpacedFont(resultImage, graphics, nameText, nameTextY, nameFont, Color.decode("#1476DF"), 30);
|
||||
|
||||
String dbtText = StrUtil.blankToDefault(cardInfo.getString("dbtText"), "");
|
||||
int dbtTextY = (resultImage.getHeight() / 2) + 200;
|
||||
Font dbtFont = new Font("cursive", Font.BOLD, 24);
|
||||
commonFont(resultImage, graphics, dbtText, dbtTextY, dbtFont, Color.WHITE);
|
||||
int dbtTextY = nameTextY + 82;
|
||||
Font dbtFont = fitFontToWidth(graphics, new Font("微软雅黑", Font.PLAIN, 36), dbtText,
|
||||
resultImage.getWidth() * 75 / 100, 22);
|
||||
commonSpacedFont(resultImage, graphics, dbtText, dbtTextY, dbtFont, Color.decode("#333333"), 8);
|
||||
|
||||
response.setContentType("image/png");
|
||||
ImageIO.write(resultImage, "png", response.getOutputStream());
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
private NutMap getCardInfo() throws IOException {
|
||||
@@ -186,6 +216,35 @@ public class TeacherCongressDelegateCardController {
|
||||
return image;
|
||||
}
|
||||
|
||||
private BufferedImage readConfigImage(String configKey, String errorMessage) throws IOException {
|
||||
String fileId = getFileIdFromConfigValue(getConfigValue(configKey));
|
||||
if (StrUtil.isBlank(fileId)) {
|
||||
throw new IOException("请先配置" + configKey);
|
||||
}
|
||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(sysFileService.download(fileId)));
|
||||
if (image == null) {
|
||||
throw new IOException(errorMessage);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private BufferedImage tintLogo(BufferedImage source, Color color) {
|
||||
BufferedImage tinted = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
for (int x = 0; x < source.getWidth(); x++) {
|
||||
for (int y = 0; y < source.getHeight(); y++) {
|
||||
Color sourceColor = new Color(source.getRGB(x, y), true);
|
||||
int luminance = (sourceColor.getRed() * 299 + sourceColor.getGreen() * 587
|
||||
+ sourceColor.getBlue() * 114) / 1000;
|
||||
int maskAlpha = Math.max(0, Math.min(255, (250 - luminance) * 25));
|
||||
int alpha = sourceColor.getAlpha() * maskAlpha / 255;
|
||||
if (alpha > 0) {
|
||||
tinted.setRGB(x, y, new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha).getRGB());
|
||||
}
|
||||
}
|
||||
}
|
||||
return tinted;
|
||||
}
|
||||
|
||||
private String getCardBackImgFileId() {
|
||||
String configValue = getConfigValue(CARD_BACK_IMG_CONFIG);
|
||||
if (StrUtil.isBlank(configValue)) {
|
||||
@@ -194,7 +253,11 @@ public class TeacherCongressDelegateCardController {
|
||||
if (StrUtil.isBlank(configValue)) {
|
||||
return "";
|
||||
}
|
||||
String firstValue = StrUtil.subBefore(configValue, ",", false);
|
||||
return getFileIdFromConfigValue(configValue);
|
||||
}
|
||||
|
||||
private String getFileIdFromConfigValue(String configValue) {
|
||||
String firstValue = StrUtil.subBefore(StrUtil.blankToDefault(configValue, ""), ",", false);
|
||||
if (firstValue.contains("id=")) {
|
||||
firstValue = StrUtil.subAfter(firstValue, "id=", true);
|
||||
firstValue = StrUtil.subBefore(firstValue, "&", false);
|
||||
@@ -215,4 +278,34 @@ public class TeacherCongressDelegateCardController {
|
||||
int textX = (resultImage.getWidth() - textWidth) / 2;
|
||||
graphics.drawString(text, textX, textY);
|
||||
}
|
||||
|
||||
private void commonSpacedFont(BufferedImage resultImage, Graphics2D graphics, String text, int textY,
|
||||
Font font, Color color, int letterSpacing) {
|
||||
graphics.setFont(font);
|
||||
graphics.setColor(color);
|
||||
FontMetrics fontMetrics = graphics.getFontMetrics();
|
||||
int textWidth = 0;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
textWidth += fontMetrics.charWidth(text.charAt(i));
|
||||
}
|
||||
textWidth += Math.max(0, text.length() - 1) * letterSpacing;
|
||||
int textX = (resultImage.getWidth() - textWidth) / 2;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char character = text.charAt(i);
|
||||
graphics.drawString(String.valueOf(character), textX, textY);
|
||||
textX += fontMetrics.charWidth(character) + letterSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
private Font fitFontToWidth(Graphics2D graphics, Font font, String text, int maxWidth, int minSize) {
|
||||
Font result = font;
|
||||
while (result.getSize() > minSize) {
|
||||
graphics.setFont(result);
|
||||
if (graphics.getFontMetrics().stringWidth(text) <= maxWidth) {
|
||||
break;
|
||||
}
|
||||
result = result.deriveFont((float) (result.getSize() - 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user