I get my DataMatrix code using the following line:
BitMatrix bitMatrix = new DataMatrixWriter().encode(dmie.preEncodeBarcode(dataToEncode), BarcodeFormat.DATA_MATRIX, 50, 50, null);
The input string I get contains "FNC1" (just as plain characters in the string) to mark the end of a dynamic field, and in total the string has 4 different GS1 DataMatrix Application Identifiers and their respective values.
What preEncodeBarcode() does is to replace "FNC1" with <GS>
, like so:
input = input.replaceAll("FNC1", new String(new byte[] {0x1d}));
Since otherwise I simply get "FNC1910005FNC1230202[...]" encoded in the DataMatrix, while what I want is of course <GS>
instead of the text "FNC1".
However, when replacing FNC1 with <GS>
(I've tried using '\u001c' as well), I get this very strange double-DM-code instead of a normal one:
Only if I skip replacing "FNC1" with <GS>
do I get a proper one.
Any idea how to get a proper DataMatrix code based on my <GS>
-containing String? Or am I simply doing something wrong by having <GS>
directly in the String? What should I do instead in that case to get zxing to give me a correct DataMatrix? I've been reading all over but I really can't wrap my head around this.
Update: I'm not sure, but I might be on to some strange sort of bug here. This is what I'm sending to the DataMatrixWriter once I've preprocessed the input string (spaces are ):
[d29100001 21000000049347037 24000163718 390300000002990
What I find rather obscure is that if I (at the time of writing) send input.substring(2, input.length());
or input.substring(0, input.length()-3);
then it works just fine, while if I instead remove only one (or less) character from the beginning or 2 or less from the end then I get this strange DataMatrix. What's even stranger is that this behaviour is not even consistent - if I add say 6 some random numbers at the end then it works fine, but if I then remove three of those numbers then I again I get the problem. And worst of all, an hour ago I couldn't send in input.substring(0, input.length()-3)
, but now I can.
In other words, I'm utterly perplexed.
(PS. I am using the code found here to scale the DataMatrix to the size I want, but it's zxing that gives the wrong output from the start.)
Thanks to Lachezar Dobrev over at the zxing Google group I was able to get this working as expected. As it turns out, you can hand over an EncodeHintType to the DataMatrixWriter, which forces it to apply a square shape.
This does the trick for me:
HashMap hintMap = new HashMap();
hintMap.put(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
BitMatrix bitMatrix = new DataMatrixWriter().encode(input, BarcodeFormat.DATA_MATRIX, 50, 50, hintMap);
Update some week later: As it turns out, zxing is not GS1 compatible no matter what input you give it, so the whole FNC1/ issue is besides the point. Instead, I would recommend using Okapi Barcode, which works flawlessly.
I haven't found any guides or tutorials, but based on how the Okapi Java GUI generates its barcodes I puzzled this together from the project's Make Barcode
class.
DataMatrix dataMatrix = new DataMatrix();
dataMatrix.setDataType(Symbol.DataType.GS1);
dataMatrix.setReaderInit();
dataMatrix.setPreferredSize(24); //144x144
dataMatrix.forceSquare(true);
dataMatrix.setContent(dataToEncode);
BufferedImage image = new BufferedImage((dataMatrix.getWidth() * magnification) + (2 * borderSize),
(dataMatrix.getHeight() * magnification) + (2 * borderSize), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, (dataMatrix.getWidth() * magnification) + (2 * borderSize),
(dataMatrix.getHeight() * magnification) + (2 * borderSize));
Java2DRenderer renderer = new Java2DRenderer(g2d, magnification, borderSize, Color.WHITE, Color.BLACK);
renderer.render(dataMatrix);
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
//Before Base64-encoding the image and return as a String
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(baos.toByteArray());
} catch (IOException e) {
//Do some logging
return "Something went wrong";//Return super-informative error message
}