Skip to content

Commit

Permalink
PDF417: prevent wrong position info with right side collapsing to (0,0)
Browse files Browse the repository at this point in the history
Truncated PDF417 symbols don't have a stop-guard. The top-right and
bottom-right info for those was always (0,0). This could also happen for
normal PDF417 symbols when detecting the stop-guard failed.

This patch introduces a very crude approximation of the right side of the
symbol for this case that does at least make some sense.

I consider this a fix for zxing-cpp#866. This is related to zxing-cpp#145 and zxing-cpp#340.
  • Loading branch information
axxel committed Nov 6, 2024
1 parent 33fbc21 commit 579650a
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 6 deletions.
2 changes: 2 additions & 0 deletions core/src/pdf417/PDFDecoderResultExtra.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class DecoderResultExtra : public CustomData

public:

int approxSymbolWidth = -1;

int segmentIndex() const {
return _segmentIndex;
}
Expand Down
11 changes: 9 additions & 2 deletions core/src/pdf417/PDFReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "PDFDetector.h"
#include "PDFScanningDecoder.h"
#include "PDFCodewordDecoder.h"
#include "PDFDecoderResultExtra.h"
#include "ReaderOptions.h"
#include "DecoderResult.h"
#include "DetectorResult.h"
Expand Down Expand Up @@ -85,7 +86,13 @@ static Barcodes DoDecode(const BinaryBitmap& image, bool multiple, bool tryRotat
ScanningDecoder::Decode(*detectorResult.bits, points[4], points[5], points[6], points[7],
GetMinCodewordWidth(points), GetMaxCodewordWidth(points));
if (decoderResult.isValid(returnErrors)) {
auto point = [&](int i) { return rotate(PointI(points[i].value())); };
auto point = [&](int i) {
auto meta = dynamic_cast<DecoderResultExtra*>(decoderResult.extra().get());
if (points[i].hasValue() || i < 2 || !meta)
return rotate(PointI(points[i].value()));
else
return rotate(PointI(points[i-2].value()) + PointI(meta->approxSymbolWidth, 0));
};
res.emplace_back(std::move(decoderResult), DetectorResult{{}, {point(0), point(2), point(3), point(1)}},
BarcodeFormat::PDF417);
if (!multiple)
Expand Down Expand Up @@ -306,7 +313,7 @@ Reader::decode(const BinaryBitmap& image) const
// This falls through and tries the non-pure code path if we have a checksum error. This approach is
// currently the best option to deal with 'aliased' input like e.g. 03-aliased.png
}

return FirstOrDefault(DoDecode(image, false, _opts.tryRotate(), _opts.returnErrors()));
}

Expand Down
13 changes: 9 additions & 4 deletions core/src/pdf417/PDFScanningDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "PDFCodewordDecoder.h"
#include "PDFDetectionResult.h"
#include "PDFDecoder.h"
#include "PDFDecoderResultExtra.h"
#include "PDFModulusGF.h"
#include "ZXAlgorithms.h"
#include "ZXTestSupport.h"
Expand Down Expand Up @@ -127,7 +128,7 @@ static Nullable<Codeword> DetectCodeword(const BitMatrix& image, int minColumn,
}
// TODO implement check for width and correction of black and white bars
// use start (and maybe stop pattern) to determine if blackbars are wider than white bars. If so, adjust.
// should probably done only for codewords with a lot more than 17 bits.
// should probably done only for codewords with a lot more than 17 bits.
// The following fixes 10-1.png, which has wide black bars and small white bars
// for (int i = 0; i < moduleBitCount.length; i++) {
// if (i % 2 == 0) {
Expand Down Expand Up @@ -674,7 +675,7 @@ static DecoderResult CreateDecoderResult(DetectionResult& detectionResult)

// TODO don't pass in minCodewordWidth and maxCodewordWidth, pass in barcode columns for start and stop pattern
// columns. That way width can be deducted from the pattern column.
// This approach also allows detecting more details about the barcode, e.g. if a bar type (white or black) is wider
// This approach also allows detecting more details about the barcode, e.g. if a bar type (white or black) is wider
// than it should be. This can happen if the scanner used a bad blackpoint.
DecoderResult
ScanningDecoder::Decode(const BitMatrix& image, const Nullable<ResultPoint>& imageTopLeft, const Nullable<ResultPoint>& imageBottomLeft,
Expand All @@ -685,7 +686,7 @@ ScanningDecoder::Decode(const BitMatrix& image, const Nullable<ResultPoint>& ima
if (!BoundingBox::Create(image.width(), image.height(), imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, boundingBox)) {
return {};
}

Nullable<DetectionResultColumn> leftRowIndicatorColumn, rightRowIndicatorColumn;
DetectionResult detectionResult;
for (int i = 0; i < 2; i++) {
Expand Down Expand Up @@ -739,7 +740,11 @@ ScanningDecoder::Decode(const BitMatrix& image, const Nullable<ResultPoint>& ima
}
}
}
return CreateDecoderResult(detectionResult);
auto res = CreateDecoderResult(detectionResult);
auto meta = dynamic_cast<DecoderResultExtra*>(res.extra().get());
if (meta)
meta->approxSymbolWidth = (detectionResult.barcodeColumnCount() + 2) * (minCodewordWidth + maxCodewordWidth) / 2;
return res;
}

} // Pdf417
Expand Down

0 comments on commit 579650a

Please sign in to comment.