package com.ruoyi.service.impl; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; import com.google.zxing.oned.Code128Writer; import com.google.zxing.oned.Code39Writer; import org.krysalis.barcode4j.impl.code128.Code128Bean; import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider; import org.springframework.stereotype.Service; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @Service public class BarcodeService { /** * 添加文字到条码(优化版本) */ private void addTextToBarcode(Graphics2D g2d, String text, int width, int barcodeHeight) { g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // 使用更清晰的字体 Font font = new Font("Tahoma", Font.PLAIN, 45); g2d.setFont(font); g2d.setColor(Color.BLACK); // 计算文字位置 FontMetrics fm = g2d.getFontMetrics(); int textWidth = fm.stringWidth(text); int textHeight = fm.getHeight(); // 居中对齐 int x = (width - textWidth) / 2; int y = barcodeHeight + textHeight - fm.getDescent(); // 精确垂直居中 // 绘制文字 g2d.drawString(text, x, y); } public byte[] generateBarcodeImage(String barcodeText) { try { BarcodeFormat format = BarcodeFormat.CODE_39; Code39Writer writer = new Code39Writer(); // 编码参数 - 设置边距为0 Map hints = new HashMap<>(); hints.put(EncodeHintType.MARGIN, 0); // 关键:设置边距为0 // 生成 BitMatrix(纯条码,无文字) // 注意:即使设置了MARGIN=0,ZXing可能仍会保留最小边距 BitMatrix matrix = writer.encode(barcodeText, format, 1300, 141, hints); // 方案1.1:直接裁剪白边 return generateBarcodeWithCroppedMargin(matrix, barcodeText); } catch (IOException e) { throw new RuntimeException("Error generating barcode", e); } catch (WriterException e) { throw new RuntimeException(e); } } private byte[] generateBarcodeWithCroppedMargin(BitMatrix matrix, String barcodeText) throws IOException { int width = matrix.getWidth(); int height = matrix.getHeight(); // 找到条码的实际边界 int left = findLeftBoundary(matrix); int right = findRightBoundary(matrix); int top = findTopBoundary(matrix); int bottom = findBottomBoundary(matrix); // 计算条码的实际宽度和高度 int barcodeWidth = right - left + 1; int barcodeHeight = bottom - top + 1; // 计算文字区域高度 int textAreaHeight = 30 + 27; // 创建最终图像(精确尺寸) BufferedImage finalImage = new BufferedImage( barcodeWidth, barcodeHeight + textAreaHeight, BufferedImage.TYPE_BYTE_BINARY ); Graphics2D g2d = finalImage.createGraphics(); // 白色背景 g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, barcodeWidth, barcodeHeight + textAreaHeight); // 绘制条码(只绘制有效部分) g2d.setColor(Color.BLACK); for (int x = left; x <= right; x++) { for (int y = top; y <= bottom; y++) { if (matrix.get(x, y)) { g2d.fillRect(x - left, y - top, 1, 1); } } } // 添加自定义文字 addTextToBarcode(g2d, barcodeText, barcodeWidth, barcodeHeight); g2d.dispose(); // 保存 ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); ImageIO.write(finalImage, "png", resultStream); return resultStream.toByteArray(); } // 辅助方法:找到条码的边界 private int findLeftBoundary(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (matrix.get(x, y)) { return x; } } } return 0; } private int findRightBoundary(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); for (int x = width - 1; x >= 0; x--) { for (int y = 0; y < height; y++) { if (matrix.get(x, y)) { return x; } } } return width - 1; } private int findTopBoundary(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (matrix.get(x, y)) { return y; } } } return 0; } private int findBottomBoundary(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); for (int y = height - 1; y >= 0; y--) { for (int x = 0; x < width; x++) { if (matrix.get(x, y)) { return y; } } } return height - 1; } public byte[] generateBarcodeImage1(String barcodeText) { try { // 使用 BitMatrix 生成纯条码,不包含任何文字 BarcodeFormat format = BarcodeFormat.CODE_39; // 根据您的条码类型 // 创建编码器 Code39Writer writer = new Code39Writer(); // 编码参数 Map hints = new HashMap<>(); hints.put(EncodeHintType.MARGIN, 0); // 无边框 // 生成 BitMatrix(纯条码,无文字) BitMatrix matrix = writer.encode(barcodeText, format, 1128, 199, hints); int width = matrix.getWidth(); int height = matrix.getHeight(); // 计算文字区域 int textAreaHeight = 30 + 10; // 创建最终图像 BufferedImage finalImage = new BufferedImage( width, height + textAreaHeight, BufferedImage.TYPE_BYTE_BINARY ); Graphics2D g2d = finalImage.createGraphics(); // 白色背景 g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, width, height + textAreaHeight); // 绘制条码(从 BitMatrix) g2d.setColor(Color.BLACK); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (matrix.get(x, y)) { g2d.fillRect(x, y, 1, 1); } } } // 添加自定义文字 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); Font font = new Font("Tahoma", Font.PLAIN, 18); g2d.setFont(font); FontMetrics fm = g2d.getFontMetrics(); int textWidth = fm.stringWidth(barcodeText); int x = (width - textWidth) / 2; int y = height + 30 - 5; // 调整垂直位置 g2d.drawString(barcodeText, x, y); g2d.dispose(); // 保存 ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); ImageIO.write(finalImage, "png", resultStream); return resultStream.toByteArray(); // return outputStream.toByteArray(); } catch (IOException e) { throw new RuntimeException("Error generating barcode", e); } catch (WriterException e) { throw new RuntimeException(e); } } public byte[] generateBarcodeImageScarn(String barcodeText) { try { // 使用 BitMatrix 生成纯条码,不包含任何文字 BarcodeFormat format = BarcodeFormat.CODE_39; // 根据您的条码类型 // 创建编码器 Code39Writer writer = new Code39Writer(); // 编码参数 Map hints = new HashMap<>(); hints.put(EncodeHintType.MARGIN, 0); // 无边框 // 生成 BitMatrix(纯条码,无文字) BitMatrix matrix = writer.encode(barcodeText, format, 230, 63, hints); int width = matrix.getWidth(); int height = matrix.getHeight(); // 计算文字区域 int textAreaHeight = 30 + 10; // 创建最终图像 BufferedImage finalImage = new BufferedImage( width, height + textAreaHeight, BufferedImage.TYPE_BYTE_BINARY ); Graphics2D g2d = finalImage.createGraphics(); // 白色背景 g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, width, height + textAreaHeight); // 绘制条码(从 BitMatrix) g2d.setColor(Color.BLACK); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (matrix.get(x, y)) { g2d.fillRect(x, y, 1, 1); } } } // 添加自定义文字 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); Font font = new Font("Tahoma", Font.PLAIN, 18); g2d.setFont(font); FontMetrics fm = g2d.getFontMetrics(); int textWidth = fm.stringWidth(barcodeText); int x = (width - textWidth) / 2; int y = height + 30 - 5; // 调整垂直位置 g2d.drawString(barcodeText, x, y); g2d.dispose(); // 保存 ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); ImageIO.write(finalImage, "png", resultStream); return resultStream.toByteArray(); // return outputStream.toByteArray(); } catch (IOException e) { throw new RuntimeException("Error generating barcode", e); } catch (WriterException e) { throw new RuntimeException(e); } } }