Browse Source

默认字体 ARIAL UNICODE MS.TTF

master
han\hanst 1 month ago
parent
commit
b52fc17cdc
  1. 4
      src/main/java/com/gaotao/modules/base/service/Impl/BaseServiceImpl.java
  2. 9
      src/main/java/com/gaotao/modules/base/service/Impl/FontServiceImpl.java
  3. 300
      src/main/java/com/gaotao/modules/base/utils/ZplGenerator.java

4
src/main/java/com/gaotao/modules/base/service/Impl/BaseServiceImpl.java

@ -242,9 +242,9 @@ public class BaseServiceImpl implements BaseService {
if (isBlank(inData.getCustomerId())) {
throw new XJException("客户编码不能为空!");
}
if (isBlank(inData.getAddressNo())) {
/* if (isBlank(inData.getAddressNo())) {
throw new XJException("地址编码不能为空!");
}
}*/
if (isBlank(inData.getLabelNo())) {
throw new XJException("标签编号不能为空!");
}

9
src/main/java/com/gaotao/modules/base/service/Impl/FontServiceImpl.java

@ -33,6 +33,12 @@ public class FontServiceImpl implements FontService {
// 英文字体映射
FONT_FILE_MAPPING.put("Arial", "ARIAL.TTF");
FONT_FILE_MAPPING.put("Arial Unicode MS", "ARIAL UNICODE MS.TTF");
FONT_FILE_MAPPING.put("Arial Unicode", "ARIAL UNICODE MS.TTF");
FONT_FILE_MAPPING.put("ARIAL UNICODE MS.TTF", "ARIAL UNICODE MS.TTF");
FONT_FILE_MAPPING.put("ARIALUNI.TTF", "ARIAL UNICODE MS.TTF");
FONT_FILE_MAPPING.put("default", "ARIAL UNICODE MS.TTF");
FONT_FILE_MAPPING.put("Default", "ARIAL UNICODE MS.TTF");
FONT_FILE_MAPPING.put("Times New Roman", "TIMES.TTF");
FONT_FILE_MAPPING.put("Courier New", "COUR.TTF");
FONT_FILE_MAPPING.put("Helvetica", "HELV.TTF");
@ -235,10 +241,11 @@ public class FontServiceImpl implements FontService {
// 基本字体配置
String[][] basicFontConfig = {
{"默认字体", "default", "system", "系统默认字体"},
{"默认字体", "default", "system", "ARIAL UNICODE MS.TTF"},
{"微软雅黑", "Microsoft YaHei", "chinese", "现代中文字体"},
{"宋体", "SimSun", "chinese", "传统中文字体"},
{"黑体", "SimHei", "chinese", "粗体中文字体"},
{"Arial Unicode MS", "Arial Unicode MS", "english", "Unicode全字库字体"},
{"Arial", "Arial", "english", "无衬线英文字体"},
{"Times New Roman", "Times New Roman", "english", "衬线英文字体"},
{"Courier New", "Courier New", "monospace", "等宽英文字体"}

300
src/main/java/com/gaotao/modules/base/utils/ZplGenerator.java

@ -1,6 +1,5 @@
package com.gaotao.modules.base.utils;
import com.gaotao.modules.base.entity.LabelSettingData;
import com.gaotao.modules.base.entity.ReportLabelList;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@ -17,7 +16,9 @@ import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
@ -26,6 +27,18 @@ import java.util.Map;
*/
@Slf4j
public class ZplGenerator {
private static final String DEFAULT_FONT_FILE = "ARIAL UNICODE MS.TTF";
/**
* 兼容既有标签默认字体仍绑定J槽位
* 历史模板大量依赖 default -> ^CWJ,E:* 的行为默认字体改为 ARIAL UNICODE MS 后仍保持 J 槽位
* 避免中文预览/打印丢失
*/
private static final String DEFAULT_FONT_LETTER = "J";
/**
* 打印机字体字母映射固定可识别字母
* 兜底策略未命中映射时回退默认字体避免中文/特殊字符直接丢失
*/
private static final Map<String, String> FONT_LETTER_MAP = createFontLetterMap();
private String orientation;
private Integer dpi;
@ -41,7 +54,7 @@ public class ZplGenerator {
}
public ZplGenerator(String orientation, Integer dpi, CoordinateTransformer.CanvasSize canvasSize,
com.gaotao.modules.base.service.FontService fontService) {
com.gaotao.modules.base.service.FontService fontService) {
this(orientation, dpi, canvasSize);
this.fontService = fontService;
}
@ -99,8 +112,8 @@ public class ZplGenerator {
}
CoordinateTransformer.ZplCoordinate coord = transformer.toZPL(
element.getX() != null ? element.getX() : 0,
element.getY() != null ? element.getY() : 0
element.getX() != null ? element.getX() : 0,
element.getY() != null ? element.getY() : 0
);
switch (element.getType()) {
@ -131,14 +144,15 @@ public class ZplGenerator {
// 设置字体
Integer fontSize = element.getFontSize() != null ? element.getFontSize() : 30;
String fontCommand = generateFontCommand(element, fontSize);
zpl.append(fontCommand).append("\n");
FontCommand fontCommand = generateFontCommand(element, fontSize);
zpl.append(fontCommand.getSetupCommand()).append("\n");
String fontSizeCommand = fontCommand.getFontSizeCommand();
// 如果有复选框
if (Boolean.TRUE.equals(element.getIsChecked())) {
zpl.append("^FO").append(x - 60).append(",").append(y)
.append("^GB45,45,2,B,0^FS ^FO").append(x - 50).append(",").append(y + 10)
.append("^AJN,35,35^FD√^FS\n");
.append("^GB45,45,2,B,0^FS ^FO").append(x - 50).append(",").append(y + 10)
.append("^AJN,35,35^FD√^FS\n");
}
String data = element.getData() != null ? element.getData() : "";
@ -152,13 +166,13 @@ public class ZplGenerator {
int lineWidth = Math.max(1, Math.round((element.getLineWidth() != null ? element.getLineWidth() : 200) * this.dpi / 25.4f));
int lineRows = element.getLineRows() != null ? element.getLineRows() : 2;
zpl.append("^FO").append(x).append(",").append(y)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,").append(alignmentParam).append("^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,").append(alignmentParam).append(fontSizeCommand)
.append("^FD").append(data).append("^FS");
} else {
// 单行文本
zpl.append("^FO").append(x).append(",").append(y)
.append("^FD").append(data).append("^FS");
.append("^FD").append(data).append("^FS");
}
// 加粗效果通过偏移重复打印实现
@ -167,24 +181,24 @@ public class ZplGenerator {
int lineWidth = Math.max(1, Math.round((element.getLineWidth() != null ? element.getLineWidth() : 200) * this.dpi / 25.4f));
int lineRows = element.getLineRows() != null ? element.getLineRows() : 2;
zpl.append("\n^FO").append(x + 1).append(",").append(y)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,").append(alignmentParam).append("^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,").append(alignmentParam).append(fontSizeCommand)
.append("^FD").append(data).append("^FS");
zpl.append("\n^FO").append(x).append(",").append(y + 1)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,").append(alignmentParam).append("^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,").append(alignmentParam).append(fontSizeCommand)
.append("^FD").append(data).append("^FS");
zpl.append("\n^FO").append(x + 1).append(",").append(y + 1)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,").append(alignmentParam).append("^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,").append(alignmentParam).append(fontSizeCommand)
.append("^FD").append(data).append("^FS");
} else {
zpl.append("\n^FO").append(x + 1).append(",").append(y)
.append("^FD").append(data).append("^FS");
.append("^FD").append(data).append("^FS");
zpl.append("\n^FO").append(x).append(",").append(y + 1)
.append("^FD").append(data).append("^FS");
.append("^FD").append(data).append("^FS");
zpl.append("\n^FO").append(x + 1).append(",").append(y + 1)
.append("^FD").append(data).append("^FS");
.append("^FD").append(data).append("^FS");
}
}
@ -193,7 +207,7 @@ public class ZplGenerator {
int textWidth = estimateTextWidth(data, fontSize);
int underlineY = y + fontSize + 2;
zpl.append("\n^FO").append(x).append(",").append(underlineY)
.append("^GB").append(textWidth).append(",2,2,B^FS");
.append("^GB").append(textWidth).append(",2,2,B^FS");
}
return zpl.toString();
@ -202,17 +216,150 @@ public class ZplGenerator {
/**
* 生成字体命令
*/
private String generateFontCommand(ReportLabelList element, Integer fontSize) {
StringBuilder fontCmd = new StringBuilder();
private FontCommand generateFontCommand(ReportLabelList element, Integer fontSize) {
int resolvedFontSize = fontSize != null && fontSize > 0 ? fontSize : 30;
String fontFamily = element != null ? element.getFontFamily() : null;
String resolvedFontFile = DEFAULT_FONT_FILE;
String resolvedFontLetter = DEFAULT_FONT_LETTER;
boolean useDefaultFont = fontFamily == null
|| fontFamily.trim().isEmpty()
|| "default".equalsIgnoreCase(fontFamily.trim());
boolean chineseFontFamily = isChineseFontFamily(fontFamily);
if (!useDefaultFont) {
String resolvedByConfig = resolveFontFileByFamily(fontFamily);
if (resolvedByConfig != null) {
resolvedFontFile = resolvedByConfig;
if (chineseFontFamily) {
// 与前端预览保持一致中文字体统一走J槽位避免Labelary对B/C/D等槽位兼容差异导致中文丢失
resolvedFontLetter = DEFAULT_FONT_LETTER;
} else {
String mappedLetter = FONT_LETTER_MAP.get(resolvedFontFile);
if (mappedLetter != null) {
resolvedFontLetter = mappedLetter;
} else {
// 保守兜底若字母映射缺失强制使用默认槽位避免^CF使用无效字母
log.warn("字体文件未维护字母映射,回退默认字体: {}", resolvedFontFile);
resolvedFontFile = DEFAULT_FONT_FILE;
resolvedFontLetter = DEFAULT_FONT_LETTER;
}
}
} else {
// 打印机字体可用性兜底未识别字体统一回退默认字体避免输出空白
log.warn("字体族未匹配到可用打印机字体,回退默认字体: {}", fontFamily);
resolvedFontFile = DEFAULT_FONT_FILE;
resolvedFontLetter = DEFAULT_FONT_LETTER;
}
}
// 设置字符编码
fontCmd.append("^CI28");
String setupCommand = "^CI28 ^CW" + resolvedFontLetter + ",E:" + resolvedFontFile
+ " ^CF" + resolvedFontLetter + "," + resolvedFontSize;
String fontSizeCommand = "^CF" + resolvedFontLetter + "," + resolvedFontSize;
// 字体与字母映射默认ARIAL为A
log.debug("字体命令解析: fontFamily={}, fontFile={}, fontLetter={}, useDefault={}, chineseFont={}",
fontFamily, resolvedFontFile, resolvedFontLetter, useDefaultFont, chineseFontFamily);
return new FontCommand(setupCommand, fontSizeCommand, resolvedFontFile, resolvedFontLetter, resolvedFontSize);
}
/**
* 统一解析字体文件
* 1) 优先走FontService
* 2) 再走静态映射
* 3) 修正历史扩展名差异SIMSUN.TTC -> SIMSUN.TTF
*/
private String resolveFontFileByFamily(String fontFamily) {
String trimmedFontFamily = fontFamily == null ? null : fontFamily.trim();
if (trimmedFontFamily == null || trimmedFontFamily.isEmpty()) {
return null;
}
String fontFile = null;
if (fontService != null) {
fontFile = fontService.getFontFilePath(trimmedFontFamily);
if (fontFile != null) {
log.debug("通过FontService获取字体文件: {} -> {}", trimmedFontFamily, fontFile);
}
}
if (fontFile == null) {
fontFile = mapFontFamilyToFile(trimmedFontFamily);
if (fontFile != null) {
log.debug("通过静态映射获取字体文件: {} -> {}", trimmedFontFamily, fontFile);
}
}
return normalizeFontFile(fontFile);
}
/**
* 字体文件标准化避免扩展名或大小写差异导致映射失效
*/
private String normalizeFontFile(String fontFile) {
if (fontFile == null) {
return null;
}
String normalized = fontFile.trim().toUpperCase(Locale.ROOT);
if (normalized.isEmpty()) {
return null;
}
// 修正宋体历史配置扩展名统一按项目使用的TTF处理
if ("SIMSUN.TTC".equals(normalized)) {
return "SIMSUN.TTF";
}
// 兼容历史配置中旧字体文件名统一映射到打印机当前实际字体文件
if ("ARIALUNI.TTF".equals(normalized)) {
return "ARIAL UNICODE MS.TTF";
}
return normalized;
}
/**
* 中文字体识别与前端字体处理策略保持一致
*/
private boolean isChineseFontFamily(String fontFamily) {
if (fontFamily == null) {
return false;
}
String normalized = fontFamily.trim();
if (normalized.isEmpty()) {
return false;
}
switch (normalized) {
case "Microsoft YaHei":
case "微软雅黑":
case "SimSun":
case "宋体":
case "SimHei":
case "黑体":
case "KaiTi":
case "楷体":
case "FangSong":
case "仿宋":
case "Microsoft JhengHei":
case "微軟正黑體":
case "PMingLiU":
case "DFKai-SB":
case "標楷體":
case "华文宋体":
case "华文仿宋":
case "新細明體":
case "新细明体":
case "华文楷体":
case "新宋体":
return true;
default:
return false;
}
}
/**
* 创建字体字母映射表
*/
private static Map<String, String> createFontLetterMap() {
Map<String, String> fontLetterMap = new HashMap<>();
fontLetterMap.put("ARIAL UNICODE MS.TTF", "J");
fontLetterMap.put("ARIALUNI.TTF", "J");
fontLetterMap.put("ARIAL.TTF", "A");
fontLetterMap.put("MSYH.TTF", "B");
fontLetterMap.put("SIMSUN.TTC", "C");
fontLetterMap.put("SIMSUN.TTF", "C");
fontLetterMap.put("SIMHEI.TTF", "D");
fontLetterMap.put("KAITI.TTF", "E");
fontLetterMap.put("SIMFANG.TTF", "F");
@ -229,42 +376,7 @@ public class ZplGenerator {
fontLetterMap.put("PALA.TTF", "Q");
fontLetterMap.put("GARA.TTF", "R");
fontLetterMap.put("BOOKOS.TTF", "S");
String fontFamily = element.getFontFamily();
String fontFile = null;
String fontLetter = "J"; // 默认A
if (fontFamily != null && !"default".equals(fontFamily)) {
// 优先使用FontService获取字体文件
if (fontService != null) {
fontFile = fontService.getFontFilePath(fontFamily);
log.debug("通过FontService获取字体文件: {} -> {}", fontFamily, fontFile);
}
// 如果FontService没有找到使用静态映射
if (fontFile == null) {
fontFile = mapFontFamilyToFile(fontFamily);
log.debug("通过静态映射获取字体文件: {} -> {}", fontFamily, fontFile);
}
if (fontFile != null) {
fontLetter = fontLetterMap.getOrDefault(fontFile, "A");
fontCmd.append(" ^CW").append(fontLetter).append(",E:").append(fontFile);
} else {
fontCmd.append(" ^CWA,E:ARIAL.TTF");
log.warn("未找到字体文件映射,使用默认字体: {}", fontFamily);
}
} else {
fontCmd.append(" ^CWJ,E:ARIAL.TTF");
}
// 设置字体大小中文字体用J其它用对应字母
if (fontFile != null && (fontFile.equals("MSYH.TTF") || fontFile.equals("SIMSUN.TTC") || fontFile.equals("SIMHEI.TTF")
|| fontFile.equals("KAITI.TTF") || fontFile.equals("SIMFANG.TTF"))) {
fontCmd.append(" ^CFJ,").append(fontSize);
} else {
fontCmd.append(" ^CF").append(fontLetter).append(",").append(fontSize);
}
return fontCmd.toString();
return Collections.unmodifiableMap(fontLetterMap);
}
/**
@ -291,6 +403,9 @@ public class ZplGenerator {
return "SIMFANG.TTF";
case "Arial":
return "ARIAL.TTF";
case "Arial Unicode MS":
case "Arial Unicode":
return "ARIAL UNICODE MS.TTF";
case "Times New Roman":
return "TIMES.TTF";
case "Courier New":
@ -415,7 +530,7 @@ public class ZplGenerator {
String data = element.getData() != null ? element.getData() : "";
return String.format("^FO%d,%d^BY%d%s,%d%s^FD%s^FS",
x, y, width.setScale(3, RoundingMode.HALF_UP).intValue(), zplCommand, height, additionalParams, data);
x, y, width.setScale(3, RoundingMode.HALF_UP).intValue(), zplCommand, height, additionalParams, data);
}
/**
@ -443,9 +558,9 @@ public class ZplGenerator {
// 计算文本位置二维码下方居中对齐
int textY = y + sizeInDots + 10; // 二维码下方留10个点的间距
int fontSize = Math.max(18, Math.min(25, sizeInDots / 4)); // 根据二维码大小调整字体大小
FontCommand fontCommand = generateFontCommand(element, fontSize);
// 设置中文字体支持
zpl.append("\n^CI28 ^CWJ,E:ARIAL.TTF ^CFJ,").append(fontSize);
zpl.append("\n").append(fontCommand.getSetupCommand());
// 计算文本宽度以实现居中对齐
int estimatedTextWidth = estimateTextWidth(data, fontSize);
@ -457,13 +572,13 @@ public class ZplGenerator {
int lineWidth = Math.max(sizeInDots, estimatedTextWidth);
int lineRows = Math.min(3, (data.length() + 19) / 20); // 最多3行
zpl.append("\n^FO").append(x).append(",").append(textY)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,C^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0,C").append(fontCommand.getFontSizeCommand())
.append("^FD").append(data).append("^FS");
} else {
// 单行文本
zpl.append("\n^FO").append(textX).append(",").append(textY)
.append("^FD").append(data).append("^FS");
.append("^FD").append(data).append("^FS");
}
}
@ -573,14 +688,14 @@ public class ZplGenerator {
int elementX = element.getX() != null ? element.getX() : 0;
int adjustedY = (int) Math.round(1200 - elementX) - width.intValue();
return String.format("^FO%d,%d^FWR^GB%d,%s,3,B^FS",
x, adjustedY,
element.getHeight() != null ? element.getHeight() : 3,
width.toString());
x, adjustedY,
element.getHeight() != null ? element.getHeight() : 3,
width.toString());
} else {
return String.format("^FO%d,%d^GB%s,%d,3,B^FS",
x, y,
element.getWidth() != null ? element.getWidth().toString() : "100",
element.getHeight() != null ? element.getHeight() : 3);
x, y,
element.getWidth() != null ? element.getWidth().toString() : "100",
element.getHeight() != null ? element.getHeight() : 3);
}
}
@ -590,14 +705,14 @@ public class ZplGenerator {
private String generateVerticalLineZPL(ReportLabelList element, int x, int y) {
if ("landscape".equals(this.orientation)) {
return String.format("^FO%d,%d^FWR^GB%d,%s,3,B^FS",
x, y,
element.getHeight() != null ? element.getHeight() : 100,
element.getWidth() != null ? element.getWidth().toString() : "3");
x, y,
element.getHeight() != null ? element.getHeight() : 100,
element.getWidth() != null ? element.getWidth().toString() : "3");
} else {
return String.format("^FO%d,%d^GB1,%d,%s,B^FS",
x, y,
element.getHeight() != null ? element.getHeight() : 100,
element.getWidth() != null ? element.getWidth().toString() : "3");
x, y,
element.getHeight() != null ? element.getHeight() : 100,
element.getWidth() != null ? element.getWidth().toString() : "3");
}
}
@ -612,9 +727,9 @@ public class ZplGenerator {
StringBuilder zpl = new StringBuilder();
// 设置中文字体
Integer fontSize = element.getFontSize() != null ? element.getFontSize() : 30;
zpl.append("^CI28 ^CWJ,E:ARIAL.TTF ^CFJ,").append(fontSize).append("\n");
FontCommand fontCommand = generateFontCommand(element, fontSize);
zpl.append(fontCommand.getSetupCommand()).append("\n");
// 基础文本
String data = element.getData() != null ? element.getData() : "流水号";
@ -632,4 +747,13 @@ public class ZplGenerator {
private String barcodeOrientation;
private String qrcodeOrientation;
}
@Data
private static class FontCommand {
private final String setupCommand;
private final String fontSizeCommand;
private final String fontFile;
private final String fontLetter;
private final Integer fontSize;
}
}
Loading…
Cancel
Save