fix:字体加粗
This commit is contained in:
1 parent
906a970b08
commit
5460d1471d
2 files changed
+56
-34
No files matched your search
+43
-34
@@ -75,26 +75,31 @@ public class ThermalReceiptImage {
|
||||
* @return 当前绘制器
|
||||
*/
|
||||
public ThermalReceiptImage title(String text) {
|
||||
setFont(Font.BOLD, 34);
|
||||
setFont(Font.BOLD, 42);
|
||||
drawCentered(text, 16);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制带黑色边框的大号打印次数提示。
|
||||
* 绘制带黑色边框的大号打印次数提示,文字超过可用纸宽时自动换行。
|
||||
*
|
||||
* @param text 提示文本,例如“第 1 次打印”
|
||||
* @return 当前绘制器
|
||||
*/
|
||||
public ThermalReceiptImage banner(String text) {
|
||||
setFont(Font.BOLD, 38);
|
||||
setFont(Font.BOLD, 44);
|
||||
FontMetrics metrics = graphics.getFontMetrics();
|
||||
int height = metrics.getHeight() + 30;
|
||||
List<String> lines = wrap(text == null ? "" : text, contentWidth() - 32, metrics);
|
||||
int lineHeight = metrics.getHeight() + 4;
|
||||
int height = lines.size() * lineHeight + 26;
|
||||
ensureCapacity(height + 20);
|
||||
graphics.setStroke(new BasicStroke(3F));
|
||||
graphics.drawRect(HORIZONTAL_PADDING, cursorY, contentWidth(), height);
|
||||
int x = HORIZONTAL_PADDING + Math.max(0, (contentWidth() - metrics.stringWidth(text)) / 2);
|
||||
graphics.drawString(text, x, cursorY + 15 + metrics.getAscent());
|
||||
for (int index = 0; index < lines.size(); index++) {
|
||||
String line = lines.get(index);
|
||||
int x = HORIZONTAL_PADDING + Math.max(0, (contentWidth() - metrics.stringWidth(line)) / 2);
|
||||
graphics.drawString(line, x, cursorY + 13 + index * lineHeight + metrics.getAscent());
|
||||
}
|
||||
cursorY += height + 20;
|
||||
return this;
|
||||
}
|
||||
@@ -106,34 +111,38 @@ public class ThermalReceiptImage {
|
||||
* @return 当前绘制器
|
||||
*/
|
||||
public ThermalReceiptImage verificationCode(String shortCode) {
|
||||
setFont(Font.BOLD, 52);
|
||||
setFont(Font.BOLD, 64);
|
||||
drawCentered(shortCode == null || shortCode.isBlank() ? "--" : shortCode, 18);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制一行左右键值信息,值过长时在下一行继续换行。
|
||||
* 绘制一行左右键值信息,值无法完整同行显示时整段从下一行开始并继续换行。
|
||||
*
|
||||
* @param label 左侧字段名
|
||||
* @param value 右侧字段值
|
||||
* @return 当前绘制器
|
||||
*/
|
||||
public ThermalReceiptImage keyValue(String label, String value) {
|
||||
setFont(Font.PLAIN, 25);
|
||||
setFont(Font.PLAIN, 33);
|
||||
String safeLabel = label == null ? "" : label;
|
||||
String safeValue = value == null || value.isBlank() ? "--" : value;
|
||||
FontMetrics metrics = graphics.getFontMetrics();
|
||||
int labelWidth = metrics.stringWidth(safeLabel + ":");
|
||||
int valueWidth = contentWidth() - labelWidth - 12;
|
||||
List<String> lines = wrap(safeValue, Math.max(120, valueWidth), metrics);
|
||||
int inlineValueWidth = contentWidth() - labelWidth - 12;
|
||||
boolean stackValue = metrics.stringWidth(safeValue) > inlineValueWidth;
|
||||
int valueWidth = stackValue ? contentWidth() : Math.max(120, inlineValueWidth);
|
||||
List<String> lines = wrap(safeValue, valueWidth, metrics);
|
||||
int valueLineOffset = stackValue ? 1 : 0;
|
||||
int lineHeight = metrics.getHeight() + 6;
|
||||
ensureCapacity(lines.size() * lineHeight + 10);
|
||||
ensureCapacity((lines.size() + valueLineOffset) * lineHeight + 10);
|
||||
graphics.drawString(safeLabel + ":", HORIZONTAL_PADDING, cursorY + metrics.getAscent());
|
||||
for (int index = 0; index < lines.size(); index++) {
|
||||
int x = index == 0 ? HORIZONTAL_PADDING + labelWidth + 12 : HORIZONTAL_PADDING + labelWidth + 12;
|
||||
graphics.drawString(lines.get(index), x, cursorY + index * lineHeight + metrics.getAscent());
|
||||
int x = stackValue ? HORIZONTAL_PADDING : HORIZONTAL_PADDING + labelWidth + 12;
|
||||
graphics.drawString(lines.get(index), x,
|
||||
cursorY + (index + valueLineOffset) * lineHeight + metrics.getAscent());
|
||||
}
|
||||
cursorY += lines.size() * lineHeight + 6;
|
||||
cursorY += (lines.size() + valueLineOffset) * lineHeight + 6;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -144,8 +153,8 @@ public class ThermalReceiptImage {
|
||||
* @return 当前绘制器
|
||||
*/
|
||||
public ThermalReceiptImage sectionTitle(String text) {
|
||||
setFont(Font.BOLD, 28);
|
||||
ensureCapacity(48);
|
||||
setFont(Font.BOLD, 36);
|
||||
ensureCapacity(60);
|
||||
graphics.drawString(text == null ? "" : text, HORIZONTAL_PADDING, cursorY + graphics.getFontMetrics().getAscent());
|
||||
cursorY += graphics.getFontMetrics().getHeight() + 10;
|
||||
return this;
|
||||
@@ -173,12 +182,12 @@ public class ThermalReceiptImage {
|
||||
String summary = "订餐日期:" + (orderDate == null || orderDate.isBlank() ? "--" : orderDate)
|
||||
+ " 餐段:" + (mealName == null || mealName.isBlank() ? "--" : mealName);
|
||||
|
||||
setFont(Font.BOLD, 20);
|
||||
setFont(Font.BOLD, 25);
|
||||
FontMetrics tagMetrics = graphics.getFontMetrics();
|
||||
int tagWidth = tagMetrics.stringWidth(tag) + 20;
|
||||
int tagHeight = tagMetrics.getHeight() + 6;
|
||||
|
||||
setFont(Font.BOLD, 24);
|
||||
setFont(Font.BOLD, 31);
|
||||
FontMetrics orderMetrics = graphics.getFontMetrics();
|
||||
int orderX = HORIZONTAL_PADDING + tagWidth + 14;
|
||||
int orderWidth = PAPER_WIDTH_PIXELS - HORIZONTAL_PADDING - orderX;
|
||||
@@ -186,7 +195,7 @@ public class ThermalReceiptImage {
|
||||
int orderLineHeight = orderMetrics.getHeight() + 4;
|
||||
int headerHeight = Math.max(tagHeight, orderLines.size() * orderLineHeight);
|
||||
|
||||
setFont(Font.PLAIN, 21);
|
||||
setFont(Font.PLAIN, 29);
|
||||
FontMetrics summaryMetrics = graphics.getFontMetrics();
|
||||
List<String> summaryLines = wrap(summary, contentWidth(), summaryMetrics);
|
||||
int summaryLineHeight = summaryMetrics.getHeight() + 4;
|
||||
@@ -196,20 +205,20 @@ public class ThermalReceiptImage {
|
||||
|
||||
int blockTop = cursorY;
|
||||
graphics.setColor(Color.BLACK);
|
||||
setFont(Font.BOLD, 20);
|
||||
setFont(Font.BOLD, 25);
|
||||
graphics.fillRect(HORIZONTAL_PADDING, blockTop, tagWidth, tagHeight);
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.drawString(tag, HORIZONTAL_PADDING + 10, blockTop + 3 + tagMetrics.getAscent());
|
||||
graphics.setColor(Color.BLACK);
|
||||
|
||||
setFont(Font.BOLD, 24);
|
||||
setFont(Font.BOLD, 31);
|
||||
for (int lineIndex = 0; lineIndex < orderLines.size(); lineIndex++) {
|
||||
graphics.drawString(orderLines.get(lineIndex), orderX,
|
||||
blockTop + lineIndex * orderLineHeight + orderMetrics.getAscent());
|
||||
}
|
||||
|
||||
int summaryTop = blockTop + headerHeight + 10;
|
||||
setFont(Font.PLAIN, 21);
|
||||
setFont(Font.PLAIN, 29);
|
||||
for (int lineIndex = 0; lineIndex < summaryLines.size(); lineIndex++) {
|
||||
graphics.drawString(summaryLines.get(lineIndex), HORIZONTAL_PADDING,
|
||||
summaryTop + lineIndex * summaryLineHeight + summaryMetrics.getAscent());
|
||||
@@ -273,17 +282,17 @@ public class ThermalReceiptImage {
|
||||
.filter(item -> item != null && !item.isBlank()).toList();
|
||||
int innerWidth = contentWidth() - PRODUCT_CARD_PADDING * 2;
|
||||
|
||||
setFont(Font.BOLD, 21);
|
||||
setFont(Font.BOLD, 28);
|
||||
FontMetrics tagMetrics = graphics.getFontMetrics();
|
||||
int tagHeight = tagMetrics.getHeight() + 6;
|
||||
int tagWidth = tagMetrics.stringWidth(typeLabel) + 20;
|
||||
|
||||
setFont(Font.BOLD, 26);
|
||||
setFont(Font.BOLD, 40);
|
||||
FontMetrics nameMetrics = graphics.getFontMetrics();
|
||||
List<String> nameLines = wrap(safeName, innerWidth, nameMetrics);
|
||||
int nameLineHeight = nameMetrics.getHeight() + 4;
|
||||
|
||||
setFont(Font.PLAIN, 21);
|
||||
setFont(Font.PLAIN, 29);
|
||||
FontMetrics priceMetrics = graphics.getFontMetrics();
|
||||
String priceAndQuantity = "单价 ¥" + safeUnitPrice + " x" + Math.max(0, quantity);
|
||||
String subtotalText = "小计 ¥" + safeSubtotal;
|
||||
@@ -291,7 +300,7 @@ public class ThermalReceiptImage {
|
||||
+ priceMetrics.stringWidth(subtotalText) + 24 > innerWidth;
|
||||
int priceLineHeight = priceMetrics.getHeight() + 4;
|
||||
|
||||
setFont(Font.PLAIN, 21);
|
||||
setFont(Font.PLAIN, 29);
|
||||
FontMetrics componentMetrics = graphics.getFontMetrics();
|
||||
int componentLineHeight = componentMetrics.getHeight() + 3;
|
||||
List<List<String>> componentLines = new ArrayList<>();
|
||||
@@ -313,7 +322,7 @@ public class ThermalReceiptImage {
|
||||
graphics.setStroke(new BasicStroke(combo ? 4F : 2F));
|
||||
graphics.drawRect(HORIZONTAL_PADDING, cardTop, contentWidth(), cardHeight);
|
||||
|
||||
setFont(Font.BOLD, 21);
|
||||
setFont(Font.BOLD, 28);
|
||||
if (combo) {
|
||||
graphics.fillRect(contentX, contentY, tagWidth, tagHeight);
|
||||
graphics.setColor(Color.WHITE);
|
||||
@@ -326,14 +335,14 @@ public class ThermalReceiptImage {
|
||||
}
|
||||
contentY += tagHeight + 10;
|
||||
|
||||
setFont(Font.BOLD, 26);
|
||||
setFont(Font.BOLD, 40);
|
||||
for (String line : nameLines) {
|
||||
graphics.drawString(line, contentX, contentY + nameMetrics.getAscent());
|
||||
contentY += nameLineHeight;
|
||||
}
|
||||
contentY += 8;
|
||||
|
||||
setFont(Font.PLAIN, 21);
|
||||
setFont(Font.PLAIN, 29);
|
||||
graphics.drawString(priceAndQuantity, contentX, contentY + priceMetrics.getAscent());
|
||||
if (splitPriceLine) {
|
||||
contentY += priceLineHeight;
|
||||
@@ -350,10 +359,10 @@ public class ThermalReceiptImage {
|
||||
graphics.drawLine(contentX, contentY,
|
||||
PAPER_WIDTH_PIXELS - HORIZONTAL_PADDING - PRODUCT_CARD_PADDING, contentY);
|
||||
contentY += 10;
|
||||
setFont(Font.BOLD, 21);
|
||||
setFont(Font.BOLD, 29);
|
||||
graphics.drawString("组合内容", contentX, contentY + componentMetrics.getAscent());
|
||||
contentY += componentLineHeight;
|
||||
setFont(Font.PLAIN, 21);
|
||||
setFont(Font.PLAIN, 29);
|
||||
for (List<String> lines : componentLines) {
|
||||
for (String line : lines) {
|
||||
graphics.drawString(line, contentX + CHILD_INDENT,
|
||||
@@ -376,7 +385,7 @@ public class ThermalReceiptImage {
|
||||
String safeAmount = totalAmount == null || totalAmount.isBlank() ? "--" : totalAmount;
|
||||
String label = "商品合计";
|
||||
String amount = "¥" + safeAmount;
|
||||
setFont(Font.BOLD, 30);
|
||||
setFont(Font.BOLD, 42);
|
||||
FontMetrics metrics = graphics.getFontMetrics();
|
||||
int blockHeight = metrics.getHeight() + 30;
|
||||
ensureCapacity(blockHeight + 14);
|
||||
@@ -405,7 +414,7 @@ public class ThermalReceiptImage {
|
||||
*/
|
||||
private ThermalReceiptImage item(String name, String trailing, boolean child, boolean emphasized,
|
||||
int trailingWidth) {
|
||||
setFont(emphasized ? Font.BOLD : Font.PLAIN, child ? 23 : 26);
|
||||
setFont(emphasized ? Font.BOLD : Font.PLAIN, child ? 30 : 34);
|
||||
FontMetrics metrics = graphics.getFontMetrics();
|
||||
int indent = child ? CHILD_INDENT : 0;
|
||||
String prefix = child ? "- " : "";
|
||||
|
||||
+13
@@ -45,6 +45,19 @@ class ThermalReceiptImageTest {
|
||||
assertEquals(576, voucher.getWidth());
|
||||
}
|
||||
|
||||
/** 放大后的打印提示必须按纸宽自动换行,不能裁掉多订单数量等关键信息。 */
|
||||
@Test
|
||||
void largeBannerWrapsLongTextAndGrowsCanvas() throws Exception {
|
||||
BufferedImage shortBanner = ImageIO.read(new ByteArrayInputStream(new ThermalReceiptImage()
|
||||
.banner("第 1 次打印").toPngBytes()));
|
||||
BufferedImage longBanner = ImageIO.read(new ByteArrayInputStream(new ThermalReceiptImage()
|
||||
.banner("第 12 次打印 · 100 笔预约订单合并打印").toPngBytes()));
|
||||
|
||||
assertEquals(ThermalReceiptImage.PAPER_WIDTH_PIXELS, longBanner.getWidth());
|
||||
assertTrue(longBanner.getHeight() > shortBanner.getHeight(),
|
||||
"长提示换行后必须增加票据高度,不能越过右侧纸张边界");
|
||||
}
|
||||
|
||||
/** 兑换券商品卡片应完整换行长名称和套餐组成,并随内容动态增高。 */
|
||||
@Test
|
||||
void voucherProductCardsWrapNamesAndComboComponents() throws Exception {
|
||||
|
||||
Reference in new issue
Block a user