Can't decode UPC_A and UPC_E via Java api, works fine in the android app

53 views
Skip to first unread message

Yury Skanavy

unread,
Sep 27, 2016, 5:48:18 PM9/27/16
to zxing
Hi,

I have a test program that creates a bunch of different bar/image codes and reads them back. Not all codes survive a roundtrip. For example UPC_A and UPC_E can be successfully written, but not read. Interestingly, reading the same images with the android app works perfectly fine.

Here's the relevant code snippets.

private static final LinkedHashSet<BarcodeFormat> formats = new LinkedHashSet<>();
static {
formats.add(BarcodeFormat.CODABAR);
formats.add(BarcodeFormat.CODE_39);
formats.add(BarcodeFormat.CODE_93);
formats.add(BarcodeFormat.CODE_128);
formats.add(BarcodeFormat.DATA_MATRIX);
formats.add(BarcodeFormat.EAN_8);
formats.add(BarcodeFormat.EAN_13);
formats.add(BarcodeFormat.ITF);
formats.add(BarcodeFormat.QR_CODE);
formats.add(BarcodeFormat.RSS_14);
formats.add(BarcodeFormat.RSS_EXPANDED);
formats.add(BarcodeFormat.UPC_A);
formats.add(BarcodeFormat.UPC_E);
}
...
BufferedImage read = ImageIO.read(inStream);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(read)));

HashMap<DecodeHintType, Object> decodeHints = new HashMap<DecodeHintType, Object>();
decodeHints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
decodeHints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);

MultiFormatReader reader = new MultiFormatReader();
reader.setHints(decodeHints);
Result result = reader.decodeWithState(binaryBitmap);


For UPC_A and UPC_E, decpdong fails with NotFoundException.


What's wrong? The android app uses the same value of "POSSIBLE_FORMATS" (except TRY_HARDER, but with or without it my code still fails). The sequence of api calls is also the same except a different luminance source.

What am I missing?

Thanks,
Yury

Sean Owen

unread,
Sep 28, 2016, 10:55:39 AM9/28/16
to zxing
Hm, can you attach one of the failed images? I'm lazy.

Yury Skanavy

unread,
Sep 28, 2016, 10:59:53 AM9/28/16
to Sean Owen, zxing
Here you go.

Thanks.
--
You received this message because you are subscribed to a topic in the Google Groups "zxing" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/zxing/iCODr5bZKHk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to zxing+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
zxing-test-UPC_E.png
zxing-test-UPC_A.png

Yury Skanavy

unread,
Sep 28, 2016, 11:49:17 AM9/28/16
to zxing

Another thing is even with the app the scanned values are different from what I was encoding.
Namely for UPC_A the encoded value is "12345678901", but the app gives me 123456789012.
for UPC_E, the encoded value if "12345670". It's really hard to scan, takes a lot of camera positioning and the result is 12870561. In contrast, UPC_A scans immediately.

Sean Owen

unread,
Sep 28, 2016, 5:58:52 PM9/28/16
to zxing
So, the UPC-A fails for a pretty technical reason -- not enough white space before the barcode, barely. It works when scanning off the screen or something since it's not the same image with a few pixels of margin.

The second one 'correctly' encodes 02345670, but this doesn't pass the UPC-E checksum. I don't think that's a valid number to encode? in which case ... hm, maybe the writer should reject it.

UPC-A is always 12 digits. If you supply 11, the 12th digit which is a check digit is added. So that result is correct.

Yury Skanavy

unread,
Sep 28, 2016, 6:55:40 PM9/28/16
to zxing

Thanks Sean.
Few points.

1. Yes, UPC-A image is read fine if it's generated with a larger margin. It's a bit odd though. If I specify the hint margin 5 vs margin 6, the image look like the a lot more than 1 pixel of margin was added. See attached.

2. How can my program validate the min margin value for the above (it's user-supplied). I would like to guard users from producing unreadable images.

3. In regards to UPC-E. I am a little confused here. This writer requires that I supply 8 digits and explicitly fails for 6 or 7. I am under impression that the last digit being the check digit should be the 7th? Not sure what the 8th one should be.

4. Also, analogous to UPS-A, where the check digit is added if missing from the data (which is a nice service) or validated when present, should UPC-E writer similarly allow 6 or 7?

zxing-test-UPC_A-margin6.png
zxing-test-UPC_A-margin5.png

Yury Skanavy

unread,
Sep 29, 2016, 6:32:08 PM9/29/16
to zxing
About the UPC-A reader. Having poked around the zxing code, I am quite convinced that the problem is that the UPCAWriter does not correctly add quiet space mandated by UPC-A.
Wiki says (https://en.wikipedia.org/wiki/Universal_Product_Code)

"In addition, a UPC-A symbol requires a quiet zone (extra space of 9 modules wide) before the S (start) and after the E (end) guard patterns"

UPCAWriter does not add any. It fills an area of 95 modules and then you at the mercy of the scaling algorithm and your MARGIN value so you might inadvertently get enough of a quiet zone that way.

UPCAReader, when decoding, only expects "a quiet zone at least as big as the start pattern" which is only 3 modules, not 9 (see UPCEANReader.findStartGuardPattern(BitArray row)), i.e. sounds like an opportunity for some false positives.

Sean Owen

unread,
Sep 30, 2016, 1:21:34 AM9/30/16
to zxing
Where is the check digit added in the code you mean? the UPCAWriter will compute and add it. I realize now that the UPCEWriter could do the same if given just 7 digits, I think, but doesn't. You would need to supply the correct digit that would make the equivalent 11-digit UPC-A input pass the checksum. And yeah, that's not so reasonable for the caller to figure out.

I also think it could reject 12-digit / 8-digit input respectively if it doesn't pass the checksum. I'm a little on the fence about it because it's a behavior change and maybe there is some use for encoding in this format that doesn't quite follow the checksum rule. Not sure on that.

I agree the margin handling doesn't ensure that the default (or specified) margin is enough. I can imagine letting the caller override it to be smaller but the default should end up being at least 9 x module size.

Yes I think it's bad to tolerate too little quiet zone, though I recall (from comments) that requiring more doesn't do much and causes some barcodes to fail to read. It's worth trying again now though.

You are welcome to work on these changes if interested though I can look into them too. They're small.

Yury Skanavy

unread,
Sep 30, 2016, 12:53:05 PM9/30/16
to zxing
Thanks Sean.
I am probably not to be trusted supplying patches for zxing, especially if there are backward-compatibility considerations :)

I am ok now with the quiet zone issue.  I just ensure that I supply 9 as a MARGIN hint. My previous discomfort was caused by my intention to keep MARGIN user-specifiable, but since than I decided not to, primarily due to the way is used in the calculation. It seems to be applied to the smallest code image prior to scaling to the specified size. Instead, I use MARGIN set at 0 (or 9 for UPC-A) and add am exact number of pixels to the already unscaled image. With that I am in control of MARGIN and things are good.

I also hear you on the subject of UPC-E checksum handling and backward compatibility.

Thanks again.

Yury Skanavy

unread,
Sep 30, 2016, 12:54:32 PM9/30/16
to zxing
"the already upscaled image"

Sean Owen

unread,
Sep 30, 2016, 6:42:20 PM9/30/16
to zxing
I'm tracking this at https://github.com/zxing/zxing/issues/679 and addressed the encoding issues so far.

Yury Skanavy

unread,
Sep 30, 2016, 6:43:42 PM9/30/16
to Sean Owen, zxing
Awesome, thanks Sean.

------ Original Message ------
From: "Sean Owen" <sro...@gmail.com>
Sent: 9/30/2016 6:42:20 PM
Subject: [zxing] Re: Can't decode UPC_A and UPC_E via Java api, works fine in the android app

--
Reply all
Reply to author
Forward
0 new messages