需求
公司產品需要生成條形碼並可以使用打印機清晰打印產品標簽。最終效果類似下圖

測試過程中使用的為TSC打印機。
遇到問題
起初查找了一些java條形碼生成方案。畢竟常見的有Barcode4j、zxing等。由於都能達到目的且Barcode4j條形碼相關內容代碼更方便查找故選擇了Barcode4j。下圖為官網提供的demo。(注:不同的條碼規格所對應的bean不同,圖中為Code39,其中還有Code128等等。只需使用正確的Bean即可。)

起初測試使用hp打印機(平常打印紙張的打印機)並沒有什么問題,內容也較為清楚。后來更換為TSC打印機(更為專業的條碼打印機)后發現條碼內容彎彎曲曲,掃碼槍根本無法識別。
排查問題
首先排除打印機問題,因為打印機打印其它網站生成的條形碼並沒有問題(例如菜鳥打印、lodop等)。
最終打開菜鳥打印所生成的pdf查看發現條碼內容為矢量圖。而我們項目中生成的條形碼為png格式圖片,再將png條形碼圖片添加至itext pdf中,再將pdf輸出值打印機中。
那么使用Barcode4j生成svg條形碼並再將svg加入itext中是否能夠解決問題?
經調試是可行的。
相關代碼
Barcode4j生成svg條形碼文件。
/**
* 繪制條形碼生成到流(code128)
*
* @param msg 條形碼內容
*/
@SneakyThrows
public static void generateAtCode128(String msg, String tempFilePath, Double width, Double height, Double dpi, Double fontSize) {
if (StringUtils.isEmpty(msg)) {
return;
}
Code128Bean code128Bean = new Code128Bean();
// moduleWidth影響條碼寬度,正常來說條碼內容越長條碼越長,若想要減小條碼寬度可調整下面的值。
// 條碼越密集對打印機精度要求越高!內容多還想要條碼短,需dpi更高的打印機支持。
code128Bean.setModuleWidth(UnitConv.in2mm(1.5f / dpi));
code128Bean.setBarHeight(height);
code128Bean.doQuietZone(false);
code128Bean.setFontSize(fontSize);
// 輸出到流
SVGCanvasProvider canvas = new SVGCanvasProvider(false, 0);
// 生成條形碼
code128Bean.generateBarcode(canvas, msg);
DocumentFragment frag = canvas.getDOMFragment();
TransformerFactory factory = TransformerFactory.newInstance();
Transformer trans = factory.newTransformer();
Source src = new DOMSource(frag);
Result res = new StreamResult(tempFilePath);
trans.transform(src, res);
}
itext添加svg文件(如果使用的是itext7 簡單更代碼7.0版本提供了方法,這里為itext5)
/**
* svg添加至pdf 中
*
* @param svgFilePath
* @param width
* @param height
*/
@SneakyThrows
private void pdfWriterSvg(String svgFilePath, double width, double height, float x, float y) {
final String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.STATIC);
GVTBuilder builder = new GVTBuilder();
PdfContentByte cb = pdfWriter.getDirectContent();
PdfTemplate svgTemplate = cb.createTemplate((float) width * PAG_PROPORTION, (float) height * PAG_PROPORTION);
PdfGraphics2D g2d = new PdfGraphics2D(svgTemplate, (float) width * PAG_PROPORTION, (float) height * PAG_PROPORTION);
SVGDocument city = factory.createSVGDocument("file:///" + svgFilePath);
GraphicsNode mapGraphics = builder.build(ctx, city);
mapGraphics.paint(g2d);
g2d.dispose();
cb.addTemplate(svgTemplate, x, y);
}
后續:上線后部分用戶反映條碼有概率打印不出來。由於我們測試使用的是200dpi精度的打印機也存在同樣問題,后續讓客戶使用600dpi精度的打印機后就無問題。
要想在更小的紙張,打印更多的內容,打印機的精度更加關鍵。由於600dpi的打印機太貴(某東最便宜的看了下也要7000多),我這邊也無法進行調試。
總之有條件的買工業級的打印機效果肯定會更好。
